Rails: confused about syntax for passing locals to partials

Ruby on-RailsPartial Views

Ruby on-Rails Problem Overview


Understanding Rails "magic" with regards to rendering partials (and passing locals into them).

Why does this work:

<%= render "rabbits/form" %>

And this work:

<%= render "rabbits/form", :parent => @warren, :flash => flash %>

but this does not work:

<%= render "rabbits/form", :locals => { :parent => @warren, :flash => flash } %>

But this does:

<%= render :partial =>"rabbits/form", :locals => { :parent => @warren, :flash => flash } %>

Also, how can I look up these nuances so I don't need to bother people on S.O.?

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

The short answer is the render method looks at the first argument you pass in. If you pass in a hash (which includes :partial => 'foo', :locals => {blah blah blah}) then it will pass in all of your arguments as a hash and parse them accordingly.

If you pass in a string as your first argument, it assumes the first argument is your partial name, and will pass the remainder as your locals. However, in that subsequent call, it actually assigns :locals => your_locals_argument, which in this case is the entire :locals => {locals hash}, instead of just {locals hash}; i.e. you end up with :locals => {:locals => {locals hash}}, rather than :locals => {locals hash}.

So my advice is just to always explicitly pass values the same way all the time, and you won't have problems. In order to learn about this, I went directly to the code itself (actionpack/lib/base.rb, render() method in Rails 2; Rails 3 is different). It's a good exercise.

Furthermore, don't worry about "bothering" people on SO. That's why this site exists. I even learned something from this.

Solution 2 - Ruby on-Rails

if you need to specify :locals, you need to specify :partial or :template

<%= render :partial => "rabbits/form", :locals => {...} %>

should work

Solution 3 - Ruby on-Rails

To be honost, I only know about these use cases, because I have been keeping up with Rails for the last couple of years and read the announcements that a new way of doing it has been added. I often make a mistake in it myself, but usually it's easily corrected.

It's one of those parts of Rails API that hasn't been thoroughly thought through, if you ask me. It just accumulated more and more syntactic sugar over the years, without deprecating any of the old behavior. The render method has diabetes.

To make it even worse, render behaves differently in controller and view. I also looks at the first argument's content to see if it's a file, template, action or partial. If it starts with a slash then it's a file, or something like that.

I am in favor of using the shorter notation whenever possible. Because the short notations do communicate the intent quite well. When reading it, it usually does what you think it does. Writing partials is not straight forward.

Solution 4 - Ruby on-Rails

Here is the source of render method from http://api.rubyonrails.org/classes/ActionView/Rendering.html#method-i-render:

def render(options = {}, locals = {}, &block)
  case options
  # Here is your last case
  when Hash
    if block_given?
      _render_partial(options.merge(:partial => options.delete(:layout)), &block)
    elsif options.key?(:partial)
      _render_partial(options)
    else
      template = _determine_template(options)
      lookup_context.freeze_formats(template.formats, true)
      _render_template(template, options[:layout], options)
    end
  when :update
    update_page(&block)
  else
    # here the first three cases
    _render_partial(:partial => options, :locals => locals)
  end
end

Hope this help!

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMeltemiView Question on Stackoverflow
Solution 1 - Ruby on-RailsDoug RView Answer on Stackoverflow
Solution 2 - Ruby on-RailssethvargoView Answer on Stackoverflow
Solution 3 - Ruby on-RailsiainView Answer on Stackoverflow
Solution 4 - Ruby on-RailsAndrea SalicettiView Answer on Stackoverflow