Rails: confused about syntax for passing locals to partials
Asked Answered
L

5

98

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.?

Loyola answered 9/12, 2010 at 20:0 Comment(1)
In a comment below you were saying that the rails api docs aren't that searchable. You should try this site instead: apidock.com/rails. It also has ruby and rspec on there.Gotthard
M
154

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.

Megilp answered 9/12, 2010 at 20:23 Comment(0)
R
5

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

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

should work

Rayner answered 9/12, 2010 at 20:4 Comment(6)
it has to do with the way ruby evaluates the hash if you're curious in that way.Rayner
Indeed it does work..as I specified in my question... but what I'm wondering is why? and where is this documented? only by looking at the source? And, if that's the only way to find and understand about these myriad of nuances in Rails then I'm wondering how & where to go about locating & interpreting this from the source. I can't just click on "render" and then drill down to the source (not with TextMate anyway) or can I?Loyola
ah! so you actually are interested :). Yes, the only way to figure these things out are to a.) have a hunch like you did and b.) view the source code. I have no idea how to drill down the source though... sorryRayner
ok, i'll bite...how do you look up this kind of stuff? do you just dig through your clone https://github.com/rails/rails.git? or is there a better way? Sorry but I'm relatively new to RoR and haven't yet found a good/easy/consistent way to look up Rails documentation...such that there IS any. http://api.rubyonrails.org/ isn't easily searchable. and the source from git isn't either... sighLoyola
im not an expert by any means, but I use Aptana studio. It's built on the same platform as eclipse (if you're familiar). It allows you to "click" and trace like you said. You can also do in-code search and it has built in terminal, etc. Caution - its a pretty big fileRayner
ruby <%= render "rabbits/form" foo: "bar" %> Homesick
G
2

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.

Grisby answered 9/12, 2010 at 21:40 Comment(0)
S
1

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!

Skyeskyhigh answered 9/12, 2010 at 20:22 Comment(1)
This does help, thanks! But it doesn't help me help myself...if you know what I mean...Loyola
H
0

I had a little trouble in rails 7 / ruby 3.2.1, so for thoroughness's sake:

# Works:
<%= render partial: 'publish_unpublish_button', locals: { something: 2, more: 5 } %> 

# Works:
<%= render 'publish_unpublish_button', something: 2, more: 5 %> 

# Won't work
<%= render 'publish_unpublish_button', locals: { something: 2, more: 5 } %> 
Haberdashery answered 28/2, 2023 at 0:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.