I have a partial that I want rendered with a collection and another variable. Is it possible to pass more than one variable to a partial?
To illustrate:
Category HABTM Brands
This is just semi-pseudo-code, but I want to do something like:
<% #categories.each do |c| %>
<%= c.name %>
<%= render :partial => "mypartial", :collection => c.brands, :object => c.id %>
<% end %>
The partial needs the category id as well as the "current_brand". Any ideas?
Inside of your view, you pass a hash to the :locals key-value pair in the options hash argument.
<%= render :partial => 'partial', :locals => { :foo => 'a', :bar => 'b' } %>
... and these keys become available as variables in your partials.
Foo is: <%= foo %>
Bar is: <%= bar %>
You can give a partial any number of variables with the :locals option. It takes a hash of variable names and values.
Related
++ edited to change the question to call partial recursively ++
I am writing this question after a lot of days of frustration about this simple piece of code which isn't working. I have read numerous issues with passing partials on stackoverflow and tried all the solutions I could but it doesn't work.
Calling the partial works for the first loop but from second onwards it bombs with an error
"undefined local variable or method `count' for #<#:0x2f12670>"
Notice here that the error contains a class within a class, so something fishy is happening when the partial is being called recursively.
I have a partial called _form.html.erb which calls another partial _rule_action_fields.html.erb. I need to pass a variable from the form partial to the rule_action_field partial and here is the code:
_form.html.erb: (Please note that the builder object here is being passed from code I have not pasted)
<% #folder_count = 1 %>
<% #rule.rule_actions.each do |ruleaction| %>
<%= f.fields_for :rule_actions, ruleaction do |builder| %>
<%= render( :partial => 'rule_action_fields', :locals => { :f => builder, :count => #folder_count } ) %>
<% end %>
<% #folder_count = #folder_count + 1 %>
<% end %>
_rule_action_fields.html.erb
<p id="folder_fields">
<%= count %>
<label class="form_label">Move the files to </label>
<%= f.select(:folder_id, current_user.folders.collect { |p| [p.name,p.id] }, {:include_blank => true } ) %>
</p>
Unfortunately I cant call this partial with a collection of rule_actions because of some logic which is partially in the calling code and partially in the rule_action_fields partial.
Other syntax I have tried:
<%= render :partial => 'rule_action_fields',:f => builder, :locals => { :count => folder_count } %>
<%= render :partial => 'rule_action_fields', locals => { :count => folder_count } %>
<%= render 'rule_action_fields', :count => folder_count %>
Any ideas?
This code is working fine:
<%= render 'sidebars/pages', :object => #categories = pages , :object => { #myobject => '1', #mmyobject => '2' } %>
If I change to this:
<%= render 'sidebars/pages', :object => { #categories => pages, #myobject => '1', #mmyobject => '2' } %>
Then I receive a error from the partial when it try to iterate #categories:
undefined method `each' for nil:NilClass
I'm very new to ruby and rails also, I appreciate any help.
Cheers!
When you pass an :object to a Rails partial, a local variable (not an instance variable, beginning with #) is defined within the partial which has the same name as the partial. So for the partial sidebars/_pages.html.erb, your local variable will be called pages.
The value of the pages local variable is the Hash you passed as the value of the :object option, and none of the instance variables you had in your "outer" view will be available (such as #categories or #myobject). So you'll need to access those via the pages local variable.
You're probably looking for something like this:
<%= render 'sidebars/pages', :object => { :categories => #categories, :myobject => '1', :mmyobject => '2' } %>
And in sidebars/_pages.html.erb, you might have something like this:
<p><%= pages[:myobject] %></p>
<ul>
<% pages[:categories].each do |category| %>
<li><%= category %></li>
<% end %>
</ul>
See the Rails Guide to Layouts and Rendering's Partials section for more details.
Update:
An even better solution would be to use the :locals option, which accepts a Hash whose keys become local variables with the partial. For instance:
<%= render 'sidebars/pages', :locals => { :categories => #categories, :myobject => '1', :mmyobject => '2' } %>
And in sidebars/_pages.html.erb, you might have something like this:
<p><%= myobject %></p>
<p><%= mmyobject %></p>
<ul>
<% categories.each do |category| %>
<li><%= category %></li>
<% end %>
</ul>
This line of code as mentioned above:
<%= render 'sidebars/pages', :object => #categories = pages , :object => { #myobject => '1', #mmyobject => '2' } %
Actually does not raise any errors but also does not pass #myobject and #mmyobject to the view.
Below is the correct* approach for specifying multiple objects with the render method:
<%= render 'sidebars/pages', :object => [#categories = pages, #myobject = '2'] %>
Like this I can pass multiple objects to the view, without having to define :object more than once.
*at least for my knowledge scope
On my Home#Index page, I have this:
<%= render 'home/popular_products', :collection => #products, :as => :product %>
In my Home#_popular_products view, I have this:
<div class="span2 recommended">
<%= image_tag product.image_url(:thumb).to_s %>
</div>
This is the error I keep getting:
undefined local variable or method `product' for #<#<Class:0x007f871c4f6848>:0x007f871cdb7e28>
As far as I understand it, I shouldn't even have to specify the :as attribute in my render statement - but I tried this to be explicit after just using the :collection => #products wouldn't work.
In my Home#Index Controller I have this:
#products = Product.all.sample(6)
Thoughts?
I believe you have to specify the :partial option if you want to pass in any other options. Ie:
<%= render :partial => 'home/popular_products', :collection => #products, :as => :product %>
Should work.
Do you put _popular_products.html.erb file in your app/views/home/? I think you're using partial not following convention of rails, so rails's not understood product variable. Your partial should be named _product.html.erb if you want to used like that. With that partial, you can write like this:
<%= render #products %>
Update
Solution 1
Index page:
<%= render 'popular_products', :collection => #products %>
Partial:
<%= image_tag popular_products.image_url(:thumb).to_s %>
Solution 2
Index page:
<% #products.each do |product| %>
<%= render :partial => "popular_products", :locals => { :product => product } %>
<% end %>
Partial:
<%= image_tag product.image_url(:thumb).to_s %>
I would like to pass the form_for object to a partial:
<%= form_for #price do |f| %>
...
<%= render :partial => "price_page", :object => #price, :as => :f %>
...
<% end %>
When I call:
f.radio_button
Brings the error:
undefined method `radio_button' for #<Price:0x3cb1ed0>
How can I use f as I usually would in this partial?
Try passing form object as local
<%= render :partial => "price_page", :locals=>{:f=>f} %>
You can pass form builder object as a local variable like below,
<%= form_for #price do |f| %>
<%= render :partial => "price_page", :locals => { :f => f } %>
<% end %>
in your partial file you will be receiving form builder as a local variable "f", you can use like below,
<% f.radio_button, {} %>
I ran across this question trying to figure out how to get a form builder into a partial without an additional form tag. That's the primary use case I could think of for this question, so I'm adding this answer for future visitors.
To solve my problem, I have my form_for in my layout and I render my partial passing only the model. In my partial I use fields_for.
Looks (something) like this:
= form_for #price do |f|
...
= render partial: "price_page", object: #price, as: 'price %>
...
Then, my partial has this:
= fields_for price do |f|
...
How can I pass a is_featured = true to the following partial?
<%= render :partial => 'stores', :collection => #stores %>
I only need to pass the is_featured in one place (in all other places I call the partial as above.
You can use the locals option of render
<%= render :partial => 'stores', :collection => #stores, :locals => { :is_featured => is_featured } %>
In the partial you would access it as a method:
<%= is_featured %>