Rails partial's local variable doesn't get set - ruby-on-rails

I'm confused with passing a controller's instance variable to a partial template (named after this instance variable).
Documentation from http://api.rubyonrails.org/classes/ActionView/Partials.html says:
By default PartialRenderer uses the template name for the local name of the object passed into the template. These examples are effectively the same:
<%= render :partial => "contract", :locals => { :contract => #contract } %>
<%= render :partial => "contract" %>
But in my case I can't get the same magic.
ProductsController#show:
#foo = "123456789"
show.html.erb in the following edition works (controller's #foo appears as local variable foo in the _foo.html.erb):
<%= render :partial => 'foo', :locals => { :foo => #foo } %>
But next code doesn't pass the controller's #foo variable to the _foo.html.erb partial:
<%= render :partial => 'foo' %>
Why so?

As far as I am aware, locals usually have to be passed explicitly to the partial. The only case in which it may be passed automatically is when you're passing the main object for that controller action, i.e. if you are passing the record #foo in some action for the foos controller.
In your specific case, passing #product should work automatically. If you want to pass #foo, you'll need to pass it explicitly.

Related

Render partial :collection => #array specify variable name

I am rendering a partial like this:
$("#box_container").html("<%= escape_javascript( render :partial => 'contacts/contact_tile', :collection => #contacts) %>")
Problem is that my partial is expecting the variable 'contact'.
ActionView::Template::Error (undefined local variable or method `contact'
I simply want to tell the partial to expect a variable contact. Should iterate through #contacts as contact. How do I do that?
Found this is also helpful from the docs. You aren't limited to having the variable named after the partial:
http://guides.rubyonrails.org/layouts_and_rendering.html
To use a custom local variable name within the partial, specify the
:as option in the call to the partial:
<%= render :partial => "product", :collection => #products, :as => :item %>
With this change, you can access an instance of the #products collection as the item local variable within the partial."
The documentation at http://guides.rubyonrails.org/layouts_and_rendering.html says:
When a partial is called with a pluralized collection, then the
individual instances of the partial have access to the member of the
collection being rendered via a variable named after the partial.
So it will be passed a variable called "contact_tile" instead of "contact". Perhaps you can just rename your partial.
If this naming is important, you could do it explicitly without the collection option by something like:
#contacts.each { |contact| render :partial => 'contacts/contact_tile', :locals => {:contact => contact } }
(although as a commenter pointed out, this may not be as performant)
Latest syntax are :
index.html.erb
<%= render partial: "product", collection: #products %>
_product.html.erb
<p>Product Name: <%= product.name %></p>
#products is used in partial as product
Where #products can be considered as Product.all
and product can be considered as a row of product i.e. Product.first as looped all product one by one.
You can specify a custom variable name as the default with the keyword as:
<%= render partial: 'line_items/line_item', collection: order.line_items, as: :item %>

Pass Parameters in render - Rails 3

I've seen a couple questions on this but haven't been able to solve it...
I'm trying to pass a parameter while rendering a partial (similar to domainname.com/memory_books/new?fbookupload=yes)
Right now, I use this line:
<%= render :partial => '/memory_books/new', :fbookupload => "yes" %>
and in the partial, I have tried to get the content of fbookupload by using:
<%= fbookupload %>
which gives an "undefined local variable" error and
<%= params.inspect %>
which does not show fbookupload as a parameter.
How can I have the partial pass along the parameter :fbookupload?
Thank you.
UPDATE:
Could it have anything to do with the fact that I'm rendering this within a render?
i.e. the page (/fbookphotos/show) that has
<%= render :partial => '/memory_books/new', :fbookupload => "yes" %>
is being rendered by another page with (posts/show) via:
<%= render :partial => '/fbookphotos/show' %>
so I'm rendering this within a render.
try this:
<%= render :partial => '/memory_books/new', :locals => {:fbookupload => "yes"} %>
Taking it out of the comments for posterity. This syntax is correct:
render '/memory_books/new', fbookupload: "yes"
But if there is a reference to rendering the same partial without specifying the local variables, e.g.
render '/memory_books/new'
then fbookupload variable becomes unavailable. The same applies to multiple local variables, e.g.
render 'my_partial', var1: 'qq', var2: 'qqq'
will work if only occurs once. But if there is something like that somewhere else in the code
render 'my_partial', var1: 'qq'
then the var2 will become unavailable. Go figure ...
To do it your way:
In the main view:
<% fbookupload = "yes" %>
<%= render :partial => '/memory_books/new', :locals => {:fbookupload => fbookupload} %>
And in the partial:
<%= fbookupload %>
2nd option:
Ideally in the controller, otherwise in the view, define an instance variable: #fbookupload = "yes". Then it is available everywhere. The partial will then be : <%= #fbookupload %>
Params is just request parameter, so if u want to pass it in params u have to add it to your url ?fbookupload=yes or assign it params[:fbookupload] = "yes", but i don't think that is a good idea.
But if u need to use params[:fbookupload]', u can replace it withparams[:fbookupload] || fbookupload', and pass fbookupload in locals hash for partial.
render can be called with or without the partial param, and there seems to be some confusion around the differences between these two forms.
The following two are equivalent:
<%= render "my_partial', my_param: true %>
and:
<%= render partial: "my_partial', locals: { my_param: true } %>
The first is a shorthand that allows you to omit partial:. With this shorthand, local variables are also not nested under locals:. This is explained well in the documentation (see 'Rendering the default case').
In the two cases above, you would access my_param in the partial directly with my_param.
One other source of confusion is that if you render the partial somewhere without passing my_param, then the partial will fail when it tries to access it. To get around this, you can access the local with local_assigns[:my_param] instead of my_param, which will give you nil if the param is not defined instead of erroring, as described in this documentation. Another alternative is to use defined?(my_param) before accessing it.

What's :locals for in render in rails?

Here is the API definition for render:
render(options = {}, locals = {}, &block)
Returns the result of a render that’s dictated by the options hash. The primary options are:
:partial - See ActionView::Partials.
:file - Renders an explicit template file (this used to be the old default), add :locals to pass in those.
:inline - Renders an inline template similar to how it’s done in the controller.
:text - Renders the text passed in out.
There is no explanation about what's the purpose of locals here? What's locals for?
Thanks.
To pass local variables to the partial template, as opposed to controller instance variables.
See Section 3.4.4, Passing Local Variables in the Layouts and Rendering Guide.
For example:
<%= render :partial => "account" %>
This means there is already an instance variable called #account for the partial and you pass it to the partial.
<%= render :partial => "account", :locals => { :account => #buyer } %>
This means you pass a local instance variable called #buyer to the account partial and the variable in the account partial is called #account. I.e., the hash { :account => #buyer } for :locals is just used for passing the local variable to the partial. You can also use the keyword as in the same way:
<%= render :partial => "contract", :as => :agreement
which is the same as:
<%= render :partial => "contract", :locals => { :agreement => #contract }

getting variable in partial

I've seen the other posts, but can't seem to figure out why this isn't working for me
In my controller I set
#referrer=referrer.name
in my view i have
<%= render 'js', :referrer => #referrer >
then in my partial i put
var type =' <%= referrer >';
I get a response 'undefined local variable or method 'referrer' and it points to the _js file.
from what I can see, this is exactly how it is supposed to be written, what am I doing wrong?
<%= render :partial => "account", :locals => { :referrer => #referrer } %>
Your variables to use in the partial need to be passed via the :locals hash.
Reference: http://api.rubyonrails.org/classes/ActionView/Partials.html
EDIT
The following works perfectly for me:
Controller:
def index
#referrer = "test"
end
index.html.erb
<%= render :partial => "account", :locals => { :referrer => #referrer } %>
_account.html.erb
<%=referrer%>
Turns out the reason was that in the partial, I had to call
var type='<%= #referrer %>'
not sure why all the other documentation i'd seen had it without the # symbol

Rails AJAX: My partial needs a FormBuilder instance

So I've got a form in my Rails app which uses a custom FormBuilder to give me some custom field tags
<% form_for :staff_member, #staff_member, :builder => MyFormBuilder do |f| %>
[...]
<%= render :partial => "staff_members/forms/personal_details", :locals => {:f => f, :skill_groups => #skill_groups, :staff_member => #staff_member} %>
[...]
<% end %>
Now, this partial is in an area of the form which gets replaces by an AJAX callback. What I end up doing from the controller in response to the AJAX request is:
render :partial => "staff_members/forms/personal_details", :locals => {:skill_groups => #skill_groups, :staff_member => #staff_member}
However, if I do that then the form breaks, as the FormBuilder object I used in the form_for is no longer available. Is there any way for me to use my custom FormBuilder object inside a partial used for an AJAX callback?
Use fields_for inside your partial. It performs a similar task but without wrapping the form tags. See the API docs.
how about this?
#template.with_output_buffer do
#template.form_for #model_object do |f|
f.fields_for :some_nested_attributes do |ff|
render :partial => 'nested_attributes', :object => #model_object, :locals => {:form => ff}
end
end
end
this would be especially useful is you need to use the nested fields_for in the partial
You could instantiate a new instance of your form builder in the controller, though it feels sort of lousy to me:
# in the controller
render :partial => {
:f => MyFormBuilder.new(:staff_member, #staff_member, template),
:skill_groups => #skill_groups,
:staff_member => #staff_member
}
Alternatively, you could move more of the update logic to be client side which wouldn't require you to worry about rendering anything at all. You could just update the values via JS. Not sure if that works for your project though.
Maybe I'm a little late in the game here, and maybe I don't understand the question properly, but in ApplicationHelper.rb I think you can just add the line:
ActionView::Base.default_form_builder = MyFormBuilder
You can submit within your ajax call the content of f.object_name (it's also works with partials) and use it to render tags defined in http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html passing it as the first argument.

Resources