Ruby HAML add If Condition to each.do - ruby

I have a haml ruby site that is pulling data from Salesforce. What I need to be able to do is to set an if condition based on the productCode listed in SF. The each.do establishes a loop to display the related data for each record in the loop.
The client would like productFamily specific pages. So I need to loop through all items with a product code of GEA for one page and GFE for another page.
.row
.col-xs-12
- #price_book.where(:productCode => GEA).each do |prod|
.row
.panel.panel-default
.panel-body
.col-xs-4
%img{:src => "#{prod.productUrl}", :height => "200", :width => "150"}
When I attempt to run this I get the following error:
ActionView::Template::Error (uninitialized constant ActionView::CompiledTemplates::GEA):
7:
8: .row
9: .col-xs-12
10: - #price_book.where(:productcode => GEA).each do |prod|
11:
12: .row
13: .panel.panel-default
Thank You for your assistance, I am new to Ruby and modifying another Developers code.

If #price_book is an ActiveRecord::Relation object, not just array of YourModel and productcode is String column of YourModel then you can call additional ActiveRecord methods like where:
#price_book.where(:productcode => 'GEA')
If GEA, GFE are not variables defined in view then values should be in quotes (double quotes) 'GEA', "GFE".
You can put
= #price_book.inspect
in your template and get more info about it. Tell us what kind of object is #price_book and we will give you advice.

I was able to apply the if filter logic to the loop with the following modification to the code
- #price_book.select{ |prod| prod[:productCode] == "GEA" }.each do |prod|
This returned only items from the price book with a product code of GEA

Related

Sinatra: User.first method

I'm reading a book that's making a Twitter clone with Sinatra in order to improve my knowledge of Ruby. I'm puzzled by the author's use of
User.first(:nickname => params[:recipient])
which he uses in several locations throughout the code, as in the following example.
post '/message/send' do
recipient = User.first(:nickname => params[:recipient])
Status.create(:text => params[:message], :user => User.
get(session[:userid]), :recipient => recipient)
redirect '/messages/sent'
end
What exactly is 'first' adding to this method. For example, is it searching for the first user with the nickname passed in as the parameter :recipient? In other words, is it equivalent to 'find'?
I should add that it puzzles me also because the nicknames are supposed to be unique, so there's no reason why it would need to search for the 'first' if that's indeed what it's doing.
Update
The author is using DataMapper for the ORM
Ok, 'first' is a datamapper method that 'finds'. From the docs
zoo = Zoo.first(:name => 'Metro') # first matching record with the name 'Metro'

Rails 3.1 form_for missing method

I'm working with a model that I know is working (records exist in the data base, can be searched for and displayed in other views, etc.) but when I try to use the form_for tag to generate a view for editing one of these records, I get an error message:
Showing /var/www/caucus/app/views/registration_loader/checkIn.html.erb where line #13 raised:
undefined method `voter_path' for #<#<Class:0x98cabdc>:0x98c8878>
Extracted source (around line #13):
10: </div>
11:
12: <%= form_for(
13: #voter,
14: { :controller => "registration_loader",
15: :action => "editVoter"
16: } ) do |f| %>
The #voter refers to a Voter object retrieved by:
# Get the voter.
#voter = Voter.where( [ "voter_id = ?", #voterId ] )[ 0 ]
if not #voter
flash[ :error ] = "NO VOTER!"
redirect_to :action => 'search'
elsif not #voter.kind_of?( Voter )
flash[ :error ] = "NO VOTER RECORD! (#{#voter.class.to_s})"
redirect_to :action => 'search'
end
When I change the #voter to :voter, it stops giving me the error, but does not populate the fields in my view with the data for the record I want to edit.
According to the Rails 3.1 API guide, passing a model object into form_for should generate code that allows me to edit the data in that object, but evidently there is a missing helper method (voter_path). Where is this voter_path method supposed to be defined, and what is its proper semantic and signature? Nowhere in the documentation is creating such a method discussed, nor can I find any examples of writing such a method.
Is the *_path method supposed to be auto-generated? If not, can someone point me to the documentation that specifies the syntax and semantics of this method?
Thanks,
John S.
Short answer: don't use form_for unless you have also designed your code to use "resourceful controllers". Use form_tag instead. Adding resources :voters to routes creates routes to a non-existent controller.

Postgres: Error using GROUP BY and ORDER (on heroku)

I am trying to solve my heroku problem which it seems to have problem of
We're sorry, but something went wrong.
We've been notified about this issue and we'll take a look at it shortly.
Is there any mistake I have and how to overcome it?
How can I interpret these Heroku logs?
ActionView::Template::Error (PGError: ERROR: column "microposts.created_at" must appear in the GROUP BY clause or be used in an aggregate function
2011-11-14T17:33:07+00:00 app[web.1]: : SELECT category FROM "microposts" GROUP BY category ORDER BY microposts.created_at DESC):
2011-11-14T17:33:07+00:00 app[web.1]: 2: <% #categories= Micropost.select("category").group("category")%>
2011-11-14T17:33:07+00:00 app[web.1]: 3: <% unless #categories.nil? %>
2011-11-14T17:33:07+00:00 app[web.1]: 4:
2011-11-14T17:33:07+00:00 app[web.1]: 5: <ul><% #categories.each do |category| %>
2011-11-14T17:33:07+00:00 app[web.1]: 6: <li><%= link_to category.category, :controller =>"microposts", :category => category.category, :method => 'category_list' %></li>
2011-11-14T17:33:07+00:00 app[web.1]: 7: <% end %>
2011-11-14T17:33:07+00:00 app[web.1]: 8: </ul>
micropost model (New added)
class Micropost < ActiveRecord::Base
belongs_to :users
default_scope :order => 'microposts.created_at DESC'
attr_accessible :title,:content,:category
validates :user_id, :presence => true
validates :title, :presence => true,
:length => {:maximum =>500}
validates :content, :presence => true,
:length => {:maximum =>3000}
validates :category, :presence => true
end
Your immediate problem is that you're producing invalid SQL for PostgreSQL:
SELECT category FROM "microposts" GROUP BY category ORDER BY microposts.created_at DESC
Your ORDER BY doesn't match the rest of your query. You can't use a column in a grouped query unless that column is also grouped or if the column appears in an aggregate function, that's what the error message means. The reason is that PostgreSQL won't know which row's created_at to use when a group of rows are combined by the GROUP BY clause; some databases will just silently pick a row on their own, PostgreSQL prefers to be strict and wants you to remove the ambiguity yourself.
Try specifying the order yourself:
#categories = Micropost.select("category").group("category").order("category")
Another option is to use DISTINCT instead of GROUP BY to avoid duplicates:
#categories = Micropost.select('DISTINCT(category)')
BTW, you really shouldn't be doing that sort thing in a view, you might want to move that to your controller.
Your real problem is that you're developing on top of one database while deploying on another. I'd recommend that you switch your development environment to PostgreSQL 8.3 (if you're deploying to a Heroku shared database) or PostgreSQL 9.0 (if you're deploying to a dedicated database).
Have you been developing your app on MySQL? Heroku doesn't include MySQL. It uses postgreSQL. Look at this question here - PostgreSQL GROUP BY different from MySQL?
I quote -
MySQL's totally non standards compliant GROUP BY can be emulated by Postgres' DISTINCT ON. Consider this :
mysql :
SELECT a,b,c,d,e FROM table GROUP BY a
This delivers 1 row per value of a (which one, you don't really know). Well actually you can guess, because MySQL doesn't know about hash aggregates, so it will probably use a sort... but it will only sort on a, so the order of the rows could be random. Unless it uses a multicolumn index instead of sorting. Well, anyway, it's not specified by the query.
postgres :
SELECT DISTINCT ON (a) a,b,c,d,e FROM table ORDER BY a,b,c
This delivers 1 row per value of a, this row will be the first one in the sort according to the ORDER BY specified by the query. Simple.

Ym4r can't convert to string for rails3

Here's some background of my problem:
I am on Snow Leopard
I have RVM installed(using a ruby1.9.2-head installation)
I am using rails3
I installed the ym4r using this http://github.com/guilleiguaran/ym4r_gm (and followed the tutorial)
Anyway, I added these to my controller:
#map = GMap.new("map_div")
#map.control_init(:large_map => true,:map_type => true)
#map.center_zoom_init([75.5,-42.56],4)
#map.overlay_init(GMarker.new([75.6,-42.467],:title => "Hello", :info_window => "Info! Info!"))
then these to my view:
Test <%= raw(GMap.header) %> <%= raw(#map.to_html) %> <%= raw(#map.div(:width => 600, :height => 400)) %>
well actually im using haml(does it matter?)
Test
= raw(GMap.header)
- unless #map.blank?
= raw(#map.to_html)
#map{:style => "width: 600px; height: 400px"}
problem is i keep getting a
Showing /Users/eumir/rails_apps/evo-lux/app/views/layouts/_map.html.haml where line #11 raised:
can't convert Ym4r::GmPlugin::Variable to String (Ym4r::GmPlugin::Variable#to_str gives Ym4r::GmPlugin::Variable)
Extracted source (around line #11):
9: Test
10: = raw(GMap.header)
11: = raw(#map.to_html)
12: = raw(#map.div(:width => 600, :height => 400))
which is totally weird. I can't double check with debugger(it's another error altogether...my rails cant find ruby-debugger)
so im really kinda stumped. Any help?
The following function needs to be added to class Variable in mapping.rb of the plugin.
def to_str
#variable + ";"
end
Array#* gets called in the to_html function and Ruby 1.9.2 uses to_str instead of to_s to join the values.
Ok should've RTFM. Some discoveries:
the plugin was made for the now deprecated google maps v2 API
the to_html function of the plugin is a bit off in the sense that the init variables for the html variables is an array of variables - which are being joined by a string.

Add readable field descriptions to ActiveRecord models

I'd like to add descriptions to ActiveRecord model fields to serve as basic instructions / examples for each of the fields. Basically model metadata. I can then display these in the UI (next to the fields on a form etc.)
The way I'm planning to do it is simply create a static hashtable inside the model with the field name as the key and description as the value. I.e.
FIELD_DESCRIPTIONS = {
'category' => 'Select the category it should appear within.',
'title' => 'The title should be a short but descriptive summary.',
'description' => 'Please enter a full description.'
}
etc.
Then I would create a a basic form helper that would wrap these explanations inside of a span (initially hidden and shown via jQuery) so they could be instatiated via f.field_description(:title) or something along those lines.
Anyone have any better ideas? I'd like to keep this field metadata in the model since many views could use the same information, and I also think it's nice to have descriptions within the model when you're going back to look at the code (like how DataMapper can be used right within the model to specify fields).
To give you a little more detail on what I've already done (and it works fine) here's the code. I think there has to be a prettier way of expressing these descriptions in the model, so let me know if you have any ideas.
In model:
FIELD_DESCRIPTIONS = {
'category' => 'Select the category it should appear within.',
'title' => 'The title should be a short but descriptive summary.',
'description' => 'Please enter a full description.'
}
def self.describe_field(field)
FIELD_DESCRIPTIONS[field]
end
In application_helper.rb
def field_helper(form, field)
"<span class='field_helper'>#{form.object.class.describe_field(field)}</span>"
end
In view:
<%= field_helper(f, 'title') %>
This will produce the desired output:
<span class='field_helper'>The title should be a short but descriptive summary.</span>
UPDATE:
Ok So this is the final code I'm using based on the accepted answer.
File: /config/initializers/describe_attr.rb
if defined?(ActiveRecord)
# let's us add attribute descriptions to each AR model
class ActiveRecord::Base
def self.describe_attr(*params)
attrs = params.shift
unless attrs.nil?
case attrs
when Hash
##attr_descriptions = attrs
when Symbol
return ##attr_descriptions[attrs]
end
end
##attr_descriptions ||= {}
end
end
end
File: /app/models/project.rb
describe_attr(
:category => 'Select the category the project should appear within.',
:title => 'The title should be a short but descriptive summary of the project.',
:description => 'Describe the project in detail.',
:image => 'Upload an image for the project.'
)
File: /app/helpers/application_helper.rb
# assumes you have a style defined for attr_description
def describe_attr(form, attribute)
"<span class='attr_description'>#{form.object.class.describe_attr(attribute)}</span>"
end
File: /app/views/projects/_form.html.erb
<%= describe_attr(f, :title) %>
The hash is a reasonable simple solution, but if you're on rails 2.2 or higher you might want to try the internationalization api to do this. This would also put you in a good place if you ever wanted to add translations.
Check out the i18n guide for details, but basically you would create a config/locales/en.yml that includes your column names like:
en:
labels:
category: Select the category it should appear within.
Then in your view:
<%= t('labels.category') %>
The namespace is your call of course. Also check out section 4.1.4 for a neat way to separate translations based on your current view template.
If you want to patch ActiveRecord, then you can do something like:
# Add this at the bottom of enviroment.rb
class ActiveRecord::Base
def self.field_description(*params)
attrs = params.shift
unless attrs.nil?
case attrs
when Hash
##field_description = attrs
when Symbol
return ##field_description[attrs]
end
end
##field_description ||= {}
end
end
And inside your model you can add this line like a macro:
class Product < ActiveRecord::Base
field_description :category => 'Select the category it should appear within.',:title => 'The title should be a short but descriptive summary.',:description => 'Please enter a full description.'
end
To get the value
Product.field_description : title
You can mix your solution with the label helper itself:
f.label :title, f.describe(:title)
And in your model:
FIELD_DESCRIPTIONS = {
:category => 'Select the category it should appear within.',
:title => 'The title should be a short but descriptive summary.',
:description => 'Please enter a full description.'
}
def describe(:field)
self.class::FIELD_DESCRIPTIONS[field]
end
Be sure to check out formtastic, which includes support for internationalized (or not) field labels as per matschaffer's answer.
http://github.com/justinfrench/formtastic/

Resources