How to iterate instance variables within instance variables in view? - ruby-on-rails

I'm using Rails 3.2. I have the following code:
# transports_controller.rb
#transports = %w(car bike)
#transports.each do |transport|
instance_variable_set("##{transport.pluralize}",
transport.classify.constantize.all)
end
# transports/index.html.erb
<% #transports.each do |transport| %>
<h1><%= transport.pluralize.titleize %></h1>
<% #transport.pluralize.each do |transport_item| %>
<%= transport_item.name %><br>
<% end %>
<% end %>
The controller code is correct, but the view code is wrong. #transport.pluralize.each cannot be called literally . Expected result is:
<h1>Cars</h1>
Ferrari<br>
Ford<br>
<h1>Bikes</h1>
Kawasaki<br>
Ducati<br>
How do I do this?

Just like you use instance_variable_set, there is an instance_variable_get available.

You don't have to create instance variables for this, just use an array (or a hash):
transport_classes = [Car, Bike]
#transports = transport_classes.map { |transport_class|
[transport_class, transport_class.all]
}
# this returns a nested array:
# [
# [Car, [#<Car id:1>, #<Car id:2>]],
# [Bike, [#<Bike id:1>, #<Bike id:2>]
# ]
In your view:
<% #transports.each do |transport_class, transport_items| %>
<h1><%= transport_class.to_s.pluralize.titleize %></h1>
<% transport_items.each do |transport_item| %>
<%= transport_item.name %><br>
<% end %>
<% end %>

Related

Helper method within each do loop not working

I have a loop that looks like this
<% #user.collections.each do |collection| %>
<h1 class="impact"> <%= collection.name %><br></h1>
<%= collection.stories.count %>
<% end %>
It works perfectly to show the Collections that belongs to a User, and then show how many Stories are in each Collection.
However, I want to use a helper that does this.
in the view
<% #user.collections.each do |collection| %>
<h1 class="impact"> <%= collection.name %><br></h1>
<%= number_of_stories_in_collection %>
<% end %>
in the helper
module CollectionsHelper
def number_of_stories_in_collection
collection.stories.count
end
def render_stories_count
if number_of_stories_in_collection.zero?
'No stories in this collection yet'
else
"#{number_of_stories_in_collection} #{'story'.pluralize(number_of_stories_in_collection)}"
end
end
end
I get an error that says
undefined method `stories' for #<Collection::ActiveRecord_Relation:0x007f510f504af8>
Any help is appreciated, thanks!
The 'collection' variable isn't an instance variable, so the helper can't see it.
Change your view to this:
<% #user.collections.each do |collection| %>
<h1 class="impact"> <%= collection.name %><br></h1>
<%= number_of_stories_in(collection) %>
<% end %>
And your helper method to:
def number_of_stories_in(collection)
collection.stories.count
end
This way you are passing the variable to the helper correctly.
extending #Richard's answer and little bit of optimisation to avoid n+1 queries..
<% #user.collections.includes(:stories).each do |collection| %>
<h1 class="impact"> <%= collection.name %><br></h1>
<%= render_stories_count(collection) %>
<% end %>
helper:
module CollectionsHelper
def number_of_stories_in(collection)
collection.stories.length
end
def render_stories_count(collection)
if (count = number_of_stories_in(collection)).zero?
'No stories in this collection yet'
else
"#{count} #{'story'.pluralize(count)}"
end
end
end

Ruby on rails create a new variable to make an each

i'm new into ruby on rails and i want to assign a variable to make an each like this
<% 3.times do |calendar| %>
<% test = #lessons_calendar %>
<% test.each do |lesson| %>
display html here
<% end %>
<% end %>
The thing is that in my controller i have assigned 3 variables like this #lessons_1 #lessons_2 and #lessons_3 but when i run the code it says undefined method `each' for nil:NilClass, how can i join the number created by calendar to the new variable ? Thanks
Instead of below
<% 3.times do |calendar| %>
<% test = #lessons_calendar %>
<% test.each do |lesson| %>
display html here
<% end %>
<% end %>
Make changes in your controller as well as in view as below
Controller Code
# take new variable
#lessons = []
#lessons << #lessons_1
#lessons << #lessons_2
#lessons << #lessons_3
Now do code in view file as below
<% #lessons.each do |lesson| %>
<% lesson.each do |ls| %>
your code here
<%end%>
<%end%>
Hope this will help you.
<% 3.times do |calender| %>
<%= #lessons_calendar.collect{ |lesson| Write Your Code Here }.join("").html_safe rescue 'No Record' %>
<% end %>
With in the collect iterator you can assign it to instance var if you want to. Thanks

undefined method `value' for #<CategoryItemValue::ActiveRecord_Associations_CollectionProxy:0x007ff9706d24c0>

This is so simple but isnt working. What am I missing?
controlelr
#guide = Guide.friendly.find(params[:guide_id])
#category = #guide.categories.friendly.find params[:id]
#items = #category.category_items
view
<% #items.each do |item| %>
<%= item.category_item_values.value %>
<% end %>
gives the no method error of
undefined method 'value' for #<CategoryItemValue::ActiveRecord_Associations_CollectionProxy:0x007ff9706d24c0>
There is a values column in the category_item_values table so I'm not sure what the problem is.
item.category_item_values is the CollectionProxy instance (one might think of it as of an kinda array.)
Each category_item has [likely, you did not provide sufficiently enough info to guess more precisely] many values. If the assumption above is correct, here you go:
<% #items.each do |item| %>
<% item.category_item_values.each do |value| %>
<%= value %> # or maybe (depending on your model) <%= value.value %>
<% end %>
<% end %>
You will have to loop over each of the category_item_values to get the result as this suggests <CategoryItemValue::ActiveRecord_Associations_CollectionProxy:0x007ff9706d24c0> that your category_item_value is a association.
So you could do something like
<% item.category_item_values.each do |category_item_value| %>
<%= category_item_value.value %>
<% end %>

Rails: identifying type of model in joined collection

If I make an array of records like so:
#records = Tapes.all + Discs.all
How can I identify which is which in the view and write code accordingly? Something like this is what I'm after:
<% #records.each do |record| %>
<%= record.side if record.type => :tape %>
<% end %>
Use object.class, or object.is_a?. Something like following:
<% #records.each do |record| %>
<%= record.side if record.class == Tape %>
<% end %>
Or,
<% #records.each do |record| %>
<%= record.side if record.is_a?(Tape) %>
<% end %>
May be a better approach for this is to define a method on both objects that will provide you the expect data:
class Tapes
def quack
self.side
end
...
end
class Discs
def quack
# self.something
end
...
end
Then in your template:
<% #records.each do |record| %>
<%= record.quack %>
<% end %>

Call a controller method automatically when rendering a partial

I have a partial that needs to have some controller logic run before it can render without issue. Is there some way to associate the partial with some controller logic that is run whenever it is rendered?
For example, this is what my current code looks like:
MyDataController:
class MyDataController < ApplicationController
def view
#obj = MyData.find(params[:id])
run_logic_for_partial
end
def some_method_i_dont_know_about
#obj = MyData.find(params[:id])
# Doesn't call run_logic_for_partial
end
def run_logic_for_partial
#important_hash = {}
for item in #obj.internal_array
#important_hash[item] = "Important value"
end
end
end
view.html.erb:
Name: <%= #obj.name %>
Date: <%= #obj.date %>
<%= render :partial => "my_partial" %>
some_method_i_dont_know_about.html.erb:
Name: <%= #obj.name %>
User: <%= #obj.user %>
<%# This will fail because #important_hash isn't initialized %>
<%= render :partial => "my_partial" %>
_my_partial.html.erb:
<% for item in #obj.internal_array %>
<%= item.to_s %>: <%= #important_hash[item] %>
<% end %>
How can I make sure that run_logic_for_partial is called whenever _my_partial.html.erb is rendered, even if the method isn't explicitly called from the controller? If I can't, are there any common patterns used in Rails to deal with these kinds of situations?
You should be using a views helper for this sort of logic. If you generated your resource using rails generate, a helper file for your resource should already be in your app/helpers directory. Otherwise, you can create it yourself:
# app/helpers/my_data.rb
module MyDataHelper
def run_logic_for_partial(obj)
important_hash = {}
for item in obj.internal_array
important_hash[item] = "Important value" // you'll need to modify this keying to suit your purposes
end
important_hash
end
end
Then, in your partial, pass the object you want to operate on to your helper:
# _my_partial.html.erb
<% important_hash = run_logic_for_partial(#obj) %>
<% for item in important_hash %>
<%= item.to_s %>: <%= important_hash[item] %>
<% end %>
Or:
# app/helpers/my_data.rb
module MyDataHelper
def run_logic_for_partial(item)
# Do your logic
"Important value"
end
end
# _my_partial.html.erb
<% for item in #obj.internal_array %>
<%= item.to_s %>: <%= run_logic_for_partial(item) %>
<% end %>
EDIT:
As commented Ian Kennedy points out, this logic can also reasonably be abstracted into a convenience method in your model:
# app/models/obj.rb
def important_hash
hash = {}
for item in internal_array
important_hash[item] = "Important value"
end
hash
end
Then, you'd access the important_hash attribute in the following manner in your partial:
# _my_partial.html.erb
<% for item in #obj.important_hash %>
<%= item.to_s %>: <%= item %>
<% end %>
What you're trying to do runs against the grain of how Rails controllers/views are designed to be used. It would be better to structure things a bit differently. Why not put run_logic_for_partial into a helper, and make it take an argument (rather than implicitly working on #obj)?
To see an example of a view "helper", look here: http://guides.rubyonrails.org/getting_started.html#view-helpers

Resources