Rails 3 - A better way... i'm a newbie! - ruby-on-rails

Please, can you suggest me a better way to accomplish this:
#infos = #activity.infos
#infos.each do |info|
#activity.name = info.title if info.language_id == 1
end
EDIT
In my Rails app contents can be inserted in many languages, but are displayed only in one of them. Other languages are used only as XML output.
However the main cause i'm using this approach is that without a "name" attribute i wouldn't be able to create a collection like this:
<%= collection_select(:event, :activity_id, #activities, :id, :name) %>
Can you suggest me how to accomplish this without a "name" attribute in my Activity?
Thanks!

You can do something like this.
info = #activity.infos.select{|info| info.language_id == 1}.last
#activity.name = info.title

Same as the others but using the ARrel syntax that's available in rails 3.
#activity.name = #activity.infos.where(:language_id => 1).first.title
As the others mentioned ... you might want rethink your design. If you provide more detail on why you are trying to do this we may be able to help with the underlying design that lead to this.

Well, you could lose the iteration...
#activity.name = #activity.infos.find(:first, :conditions => { :language_id => 1 }).title
but that doesn't guarantee you'll get a result (in the real world). So:
info = #activity.infos.find(:first, :conditions => { :language_id => 1 })
#activity.name = info.title unless info.nil?
But as mentioned in the comments this is a strange approach - seems like there's something structurally wrong with your app/data if you're trying to assign a value this way.

Related

Where returns column name along with value

Here is my code:
<%= DimensionVersion.where(:dimension_id => 1).select("name") %>
I expect to get a list of dimension version names where :dimension_id => 1. There are four in the database.
Instead I get this:
#<ActiveRecord::Relation:0x3d351c8>
EDIT:
I figured out how to return what I wanted (sort of) with this:
<%= DimensionVersion.select("name").where(:dimension_id => 1).all %>
Which returns:
[#<DimensionVersion name: "Default">, #<DimensionVersion name: "Test1">, #<DimensionVersion name: "Test2">, #<DimensionVersion name: "Test3">]
However, I don't want it returned with #<DimensionVersion Name: ... >. I tried removing = from the leading tag, but then nothing returned.
DimensionVersion.where(:dimension_id => 1).select("name")
I think you need the pluck method.
Rewrite the above as:
DimensionVersion.where(:dimension_id => 1).pluck(:name)
Similarly even a higher level construct like collect can be used as:
DimensionVersion.where(:dimension_id => 1).collect(&:name)
Hope this helps.
AR returns Relation so that you can chain conditions etc. If you want the actual results, call #all, #first, #each,... on it:
DimensionVersion.where(:dimension_id => 1).select("name").all
Querying with rails is such a pain in the butt I'm about to abandon the whole framework and go back to php.
You might want to read the guides: Active Record Query Interface.
I was able to get rid of the column names by using the collect method like so:
DimensionVersion.select("name").where(:dimension_id => 1).all.collect { |d| [d.name]}

Simple Form - Translating options of a input field

I'm trying to use the i18n feature of simple form, which works great in most cases.
My only problem is, that in one case I want to use numbers as option values, so I can not simply create a symbol like in the other cases. Right now, I'm using this solution:
f.input :adm, :as => :select, :collection => [[:adm11 ,"11"],
[:adm00, "00"], [:adm06, "06"], [:adm99, "99"]]
Can I somehow make simple_form look up adm11 and so on in the usual way, so I can keep a sensible structure in my translation file?
I know I could do it with standard ruby i18n, but I'm looking for a better way.
f.input :adm,
:collection => [[:adm11 ,"11"], [:adm00, "00"], [:adm06, "06"],
[:adm99, "99"]],
:label_method => lambda { |el| t "define.i18n.keys.here.#{el.first}" }
I think you can't do it because of this line in SimpleForm:
collection_translated = translate_collection if collection_classes == [Symbol]
So it means that SimpleForm translates options if it's array of symbols. See discussion here https://github.com/plataformatec/simple_form/pull/302

Cannot precheck check_box_tag in rails

I have code that looks like this:
#all_ratings.each do |rating|
= check_box_tag "ratings[#{rating}]", session[:checkbox][rating], :id => "ratings_#{rating}"
...
= submit_tag 'Refresh', :id => "ratings_submit"
By saving the state of which checkboxes were clicked I hoped to be able to pre-check the boxes that were clicked after the request had gone through and the page reloads. The problem that I am having is that the code above doesn't seem to work. I'm not sure if it's because I have the :id => "ratings_#{rating}" bit at the end (which is required for this assignment). I checked out the rails api here, but that was as clear as mud. Thanks in advance for the help!
Cheers
(Disclaimer: This code is for HW 2 for Coursera's Software as a Service course - I have finished the bulk of the logic for the HW, but this last bit is beyond me and seems to be more of an idiosyncracy than a major topic, hence I am posting it here.)
What boolean variable did you add? Considering I have a model with has_many ratings, say Video, and have #video defined, I'd do
= check_box_tag "ratings[#{rating}]", session[:checkbox][rating], #video.ratings.include?(rating), :id => "ratings_#{rating}".
The #video.ratings.include?(rating) part prechecks the ratings associated to the current video. What are the associations related to your Rating model?

How would I check if a value is found in an array of values

I want to perform an if condition where, if linkedpub.LPU_ID is found in an array of values(#associated_linked_pub), do some action.
I tried the following but the syntax is not correct.
Any suggestion is most welcomed..Thanks a lot
<% for linkedpub in Linkedpub.find(:all) %>
<% if linkedpub.LPU_ID IN #associated_linked_pub %>
# do action
<%end%>
<%end%>
You can use Array#include?
So...
if #associated_linked_pub.include? linkedpub.LPU_ID
...
Edit:
If #associated_linked_pub is a list of ActiveRecord objects then try this instead:
if #associated_linked_pub.map{|a| a.id}.include? linkedpub.LPU_ID
...
Edit:
Looking at your question in more detail, it looks like what you are doing is VERY inefficient and unscalable. Instead you could do...
For Rails 3.0:
Linkedpub.where(:id => #associated_linked_pub)
For Rails 2.x:
LinkedPub.find(:all, :conditions => { :id => #associated_linked_pub })
Rails will automatically create a SQL IN query such as:
SELECT * FROM linkedpubs WHERE id IN (34, 6, 2, 67, 8)
linkedpub.LPU_ID.in?(#associated_linked_pub.collect(&:id))
Using in? in these cases has always felt more natural to me.
if #associated_linked_pub is an array, try
if #associated_linked_pub.include?(linkedpub.LPU_ID)
#associated_linked_pub.collect(&:id).include?(linkedpub.LPU_ID)

Rails XML Builder - Code refactoring

I have written the following code in my Rails app to generate XML. I am using Aptana IDE to do Rails development and the IDE shows a warning that the code structure is identical in both the blocks. What changes can be done to the code to remove the duplicity in structure? Is there any other way to write the same?
xml.roles do
#rolesList.each do |r|
xml.role(:id => r["role_id"], :name => r["role_name"])
end
end
xml.levels do
#levelsList.each do |lvl|
xml.level(:id => lvl["level_id"], :name => lvl["level_name"])
end
end
I had the same issue with using the send method and getting tags that looked like <send:id>12</send:id>. To resolve, I used the "tag!" method. So I think your code would look like:
def build_xml(node_name, node_list)
xml.tag!(node_name.pluralize) do
node_list.each do |node|
id_str = node["#{node_name}_id"]
name_str = node["#{node_name}_name"]
xml.tag!(node_name, :id => id_str, :name => name_str)
end
end
end
I had a similar idea to #nathandva, but using send properly:
def list_to_xml(node_name, list)
xml.send(node_name.pluralize.to_sym) do
list.each do |item|
xml.send(node_name.to_sym, :id => r["#{node_name}_id"],
:name => r["#{node_name}_name"])
end
end
end
Since it adds visual complexity, this change may not be the best. The biggest question is: if you are likely to make a change to xml.roles structure, are you likely to change xml.levels as well? If so, definitely remove the duplication. It is also important to name the method something that will make sense to you upon reading it; add that point the complexity will be reduced not increased.
Something like this?
def build_xml(node_name, node_list)
xml.send(node_name.pluralize) do
node_list.each do |node|
id_str = node["#{node_name}_id"]
name_str = node["#{node_name}_name"]
xml.send(node_name, :id => id_str, :name => name_str)
end
end
end
build_xml("role", #roleslist)
build_xml("level", #levelslist)
I am trying to use send instead of eval [which i did not do to well: edited it to correct it --thanks to Kathy Van Stone].
Edit 26/12 because the xml builder will capture the send and use it as a xml branch there are two possible options, use the send method instead, like this
xml.__send__(node_name, :id => id_str, :name => name_str)
but i am not sure whether it will create a <__send__:roles> instead. You could always fall back to
eval("xml.#{node_name} :id => '#{id_str}', :name => '#{name_str}'")
which should definitely work (but eval should always be used a last resort).

Resources