views:

535

answers:

2

Ryan Bates' nifty_scaffolding, for example, does this

edit.html.erb

<%= render :partial => 'form' %>

new.html.erb

<%= render :partial => 'form' %>

_form.html.erb

<%= form_for @some_object_defined_in_action %>

That hidden state makes me feel uncomfortable, so I usually like to do this

edit.html.erb

<%= render :partial => 'form', :locals => { :object => @my_object } %>

_form.html.erb

<%= form_for object %>

So which is better: a) having partials access instance variables or b) passing a partial all the variables it needs?

I've been opting for b) as of late, but I did run into a little pickle:

some_action.html.erb

<% @dad.sons.each do |a_son| %>
<%= render :partial => 'partial', :locals => { :son => a_son } %>
<% end %>

_partial.html.erb

The son's name is <%= son.name %>
The dad's name is <%= son.dad.name %>

son.dad makes a database call to fetch the dad! So I would either have to access @dad, which would be going back to a) having partials access instance variables or I would have to pass @dad in locals, changing render :partial to <%= render :partial => 'partial', :locals => { :dad => @dad, :son => a_son } %>, and for some reason passing a bunch of vars to my partial makes me feel uncomfortable. Maybe others feel this way as well.

Hopefully that made some sense. Looking for some insight into this whole thing... Thanks!

A: 

I vote for a) for a very specific reason - DRY! If you start passing a variable - like that - the next thing you know - it's a mess - let's say you need to change the way your variable is named or something else about it - then you need to go to ALL your views and change them instead of ONE partial. Also - if you change your partial - let's say it produces a table with some result, it will change on all your views, so you'll need to know which views are used, a proper IDE should be able to help you with that, but I also like having a small comment section at the top of the view - where I just mention where it's used and why - helps another programmer and it helps you to remember in case you need to come back to a partial and modify. But the whole point of the partial is to call it WITHOUT having to pass anything from the view, so that you don't have to modify all places where partial is called from if that variable changes somehow.

Ultimately this is a design choice - and to be honest unless you are running a facebook the extra lookup you do is not that big of a deal, but it's just not very DRY.

P.S.: Just thought about it - you can actually abstract the way you call partial in a helper method, so then if the way you call your partial needs to change - then you just need to modify one place.

Nick Gorbikoff
+8  A: 

In recent versions of Rails it is quite a bit easier to render partials and pass locals to them. Instead of this.

<%= render :partial => 'form', :locals => { :item => @item } %>

You can do this.

<%= render 'form', :item => @item %>

I don't do this in the Nifty Scaffold generator to keep backwards compatibility, but I'll change this in a future release.

As for whether it's acceptable to use instance variables in partials. I think it is. In all practicality, what is the downside? Certainly things can get out of hand if you aren't consistent, but I like to apply these guidelines.

  1. Never create an instance variable just to share it between partials. Usually this means you will only be sharing the controller resource object.

  2. If the partial is the same name as the resource, pass it as a local with <%= render @item %>.

  3. If the partial will be shared across multiple controllers then only use locals.

This is what works well for me anyway.

Bonus tip: if you find yourself passing in a lot of locals into a partial and you want some of them to be optional, create a helper method which renders the partial. Then always go through the helper method so you can make a clean interface with optional args for rendering the partial.

ryanb