Rails partials should be explicitly called with locals
Since Rails partials can see all the @variables of their parent view it’s pretty common to see partials with @’s all over the place. But the cool thing about partials is reusing them in other views and if you do you have to remember to populate all the stuff it needs and name everything the way it wants. Bah, I say. More and more I find myself explicitly calling partials with locals even if seems a bit redundant:
It goes along with this "partials are like methods" analogy I’ve been thinking about lately. And in big complicated pages with lots ‘o partials everything seems more clear. What do you think?
<%= render(:partial => 'content/poll',
:locals => {:poll => @poll}) %>
It goes along with this "partials are like methods" analogy I’ve been thinking about lately. And in big complicated pages with lots ‘o partials everything seems more clear. What do you think?
Comments
Any time a partial is going to be shared, it should definitely be called with explicit locals, and even if you don't think that you're going to share, you might in the future, so you might as well go all out and just explicitly define locals in all cases.
def copy_instance_variables()
instance_variables.inject({}) do |hash,name|
name_as_symbol = name[1..name.size].to_sym
hash[name_as_symbol] = instance_variable_get(name)
hash
end
end
Certainly more convenient. You could use instance_eval in conjunction with this to get a variables-hash for whatever object you wanted too...
render(:partial => 'content/poll', :object => @poll)
which gives you a local variable 'poll' within your partial. The name of the local variable when using :object and :collection options is always set to the name of the partial.
I agree wholeheartedly -- I've been doing this for quite a while now. I've found it tends to make my partials converge to an "API" that is reusable as well, or if not it sets me to thinking if I'm doing the right thing and maybe should refactor early on.
Also, it's a real code smell to use the partial name as the magical object variable within the partial. If you want a long descriptive name you're making a long variable name (which may not be descriptive inside the partial), or if your partial is named _show then you've got a 'show' variable in the partial, which is usually non-intuitive. Worse, if you move the partial or rename it you not only have the calls to the partial to worry about but you also have to edit the partial to rename the magic variable. Smelly.
Anyway, using :locals you get as many variables as you need as part of the API, the API is explicit.
I go so far as to occasionally grep for '@' in partials to see what I might've missed.
Best,
Rick
This way I can make sure that all the API-ish stuff for a partial, such as required locals, is handled in a single place and all methods that need to render that partial must do so through a Helper-provided method.
In other words, how to pass locals as input/output parameters?