Is it possible to loop over an object's attributes in Rails? I have an object and rather than code up each attribute in the view, I want to output each of them in the view as there are quite a few.
I have an object called #work_profile which has many attributes, mainly boolean check box values.
Edit: I see I can use #work_profile.attributes. Any help on formatting the hash into something more user friendly would be great.
The ActiveRecord::Base.attributes() method returns a hash of all the attributes. You can use that to loop over all attributes.
#work_profile.attributes.each do |attr_name, attr_value|
...
end
In a view, this would give:
<% #work_profile.attributes.each do |attr_name, attr_value| %>
<div class="work_profile_attribute">
<%= attr_name %>: <%= attr_value %>
</div>
<% end %>
Related
I'm trying to experiment with blocks and how to iterate over collections in ERB. I have a models in a one-to-many relatinship (Channel and their corresponding types).
controller
class HomePageController < ActionController
def index
#channels = Channel.all
end
end
Then in the view, I iterate over all the attributes belonging to a Channel. When I want to print all types, this code gives me the desired output:
view
<% #channels.each do |channel| %>
<% #types.each do |type| %>
<%= Type.find(type).name %>
<% end %>
<% end %>
At first I tried to achieve this by using the yield keyword in a neat one-liner but I couldn't manage to print anything to the browser, only to the console
<% #types.each {|type| yield Type.find(type).name } %>
Is there an equivalent one-liner?
First of all this method is so inefficient, you are doing n-queries, to find each record of type Type instead convert those into an array of types by using a single query in the controller, assume that that array is in type_ids
# controller
#channels = Channel.includes(:types) # avoiding n+1 queries
# view
<% #channels.each do |channel| %>
# some channel info output
<% channel.types.each do |type| %>
<%= type.name %>
<% end %> # types loop
<% end %> # channel loop
As #Almaron mentioned, you could render a partial for more simplification, if you have a partial called _type.html.erb you can call render directly
# view
<%= render channel.types %>
Rails will do all the iterating and rendering.
First of all, this kind of code does not belong to the view. Don't tackle the database from the view (in your case Type.find()). Move it to the controller where it belongs.
The second thing to note is the difference between <%= and <% tags. The first one outputs the returned result, while the second one doesn't. The problem with .each is that it returns the object it has been used on, so in your case if you just go <%= #types.each {|type| Type.find(type).name } %> you'll get the #types array printed out.
If you want to simplify that code, you can use a helper method for iterating and a partial for rendering each item. That way you get something like this
<% collection_iterate #items, 'item_partial' %>
so I have a standard has_many through association in my models, very similar to the question here: Loop through ActiveRecord::Associations::CollectionProxy with each
I used the advice in that problem but I think I am having some trouble getting it through on my ERB file so that it shows up in my app. At the moment I have the following:
<%= #memberships.map do |a| %>
<%=a.name%>
<% end %>
In this scenario, the membership model is the one through which users and organizations have many though (#memberships = #user.organizations). So the #memberships.class returns
ActiveRecord::Associations::CollectionProxy::ActiveRecord_Associations_CollectionProxy_Organization
on the rails console. So the moment, in the browser the code returns on a page where the user is in two orgs:
orgone orgtwo["\n", "\n"]
I just don't know how to manipulate the proxy classes to return what I want. Thanks!
UPDATE:
I figured it out, I had to remove the = at the top of the block, and I added some styling with a comma:
<% #memberships.map do |a| %>
<h3><%=a.name %> <%= ", " unless a == #memberships.last %></h3>
<% end %>
If you want to print the name of each membership, what you want is
<% #memberships.each do |membership| %>
<%= membership.name %>
<% end -%>
The <% prefix in ERB executes code without appending the results to the output buffer, while the <%= prefix outputs the string representation of the result of the expression. Since each returns an enumerator, a <%= will return the string representation of the enumerator which is something like #<Enumerator:0xDEADBEEF.
A really simple question but I just can't seem to get it working.
There is only one Property included below but there could be more than one within Properties. How can I iterate through this hash and display just the Name of each Property?
{"GetPropertiesResponse"=>{"Properties"=>{"Property"=>{"Breakfast"=>"IN", "Country"=>"GB", "Currency"=>"GBP", "Id"=>"1834", "Name"=>"Hotel Name"}}}}
I've tried this in my view:
<% #json['GetPropertiesResponse']['Properties']['Property'].each do |property| %>
<%= property['Name'] %>
<% end %>
I'm getting this error:
no implicit conversion of String into Integer
If you are saying there might be more than one property hash then this should work:
<% #json['GetPropertiesResponse']['Properties'].each do |property, value| %>
<%= value['Name'] %>
<% end %>
I would use #each_value on this hash since you don't appear to be using the keys
<% #json['GetPropertiesResponse']['Properties'].each_value do |value| %>
<%= value['Name'] %>
<% end %>
Should work. Note that the second line is <%= value['Name'] %> and not <%= property['Name'] %>
P.S. On a different note, I don't know why you're using the key "Property" inside of your Properties hash. That just seems like a good way to confuse yourself in exactly this way. Your keys within the Properties hash should be something unique to the property they describe. Since each will be a property, the string "Property" doesn't help describe or differentiate.
OK I'm sure I'm missing something here, but please forgive me I'm new to Rails.
Is there some way in Rails to display all the fields for an object rather than specifying each?
In my show.html template rather than going
<p>Name: <%=h #user.full_name %></p>
<p>Email: <%=h #user.email %></p>
I just want a oneliner to do this without having to type out each of the 15 or so fields I have.
Its an admin page so its fine if all the fields are shown (id, created_at, etc.)
If this was PHP it would take me about 5 secs using foreach, but I've googled (on the wrong things obviously) for an hour with no luck.
Thanks!
Something like
<% for attribute in #user.attributes.keys %>
<p><%= attribute.humanize %> <%= #user.attributes[attribute].to_s %></p>
<% end %>
could do the trick.
Matt
I suppose you want to display all attributes of a row from database table which is defined as ActiveRecord model. You can use class method column_names (every ActiveRecord model has it), which returns names of table columns in an array.
<%= User.column_names.collect { |col_name| "#{col_name.capitalize}: <p>#{#user[col_name]}</p>" }.join("\n") %>
<%= debug #user %>
simple way to show the object... that is what I usually use anyway!
#user.attributes.each{|key, value| puts "#{key} : #{value}"}
This is the snippet I used to blacklist some attributes I didn't want to show...
controller (user_controller.rb)
def show
keys_blacklist = %W(user_id name) #these are the fields to hide
#user_showlist = #user.attributes.except(*keys_blacklist)
end
view (show.html.erb):
<!-- language: ruby --><% for attribute in #user_showlist.keys %>
<b><%= attribute.humanize %></b>
<%= #user.attributes[attribute].to_s %>
<!-- language: ruby --><% end %>
You can also use instead:
#user_showlist = #user.attributes.slice(*keys_whitelist)
in order to display a whilelist of properties.
If you are using haml and want to loop through the attributes on for example a user object in a view:
- for attribute in #user.attributes.keys
%p
= attribute.humanize
= #user.attributes[attribute].to_s
In reference to this
I've created a question in a webform like this:
<div class="form_row">
<label for="features[]">Features:</label>
<% [ 'scenarios', 'role_profiles', 'private_messages', 'polls' ].each do |feature| %>
<br><%= check_box_tag 'features[]', feature,
(params[:features] || {}).include?(feature) %>
<% end %>
</div>
So if scenarios and private_messages gets checked and I print out params[:features] I will get:
scenariosprivate_messages
I was wondering how would I be able to obtain scenarios and private_messages separately from params. Is the mapping params[:features] = "scenariosprivate_messages" or is it really params[features] = ["scenarios", "private_messages"] ? If it's the latter how can I loop through them?
I write in my view:
<%= params[:features].each {|param|
param.capitalize
} %>
and I still just get scenariosprivate_messages printed.
Try this instead:
<% params[:features].each do |param| %>
<%= param.capitalize %>
<% end %>
The problem with your original solution is that you're printing out the result of the block, which is the array itself, rather than printing out each element of the array.
You shouldn't be using params in your views. You're best off assigning params[:features] to an instance variable in your controller and then iterating over that in your view.
But to answer your question, you're putting the equals sign for output in the wrong place. You want to output each element of the array individually instead of outputting the result of the loop.
You must use humanize:
<% params[:features].each do |param| %>
<%= param.humanize %>
<% end %>
According to this blog post you should be able to access them individually as params[:features]['scenarios'] etc. Looping should just work like with all other arrays -- eg
params[:features].each { |param|
# do something with param
}