Partial :object vs instance var

I’m questioning what appears to be a recommendation that makes no sense
in AWDWR 2nd Ed. I get the point being made, but the actual
convention/implementation seems to make the point ineffective.

If I have a controller Company with an action aboutus and an instance
var of @contactInfo (a hash), and I have a view called aboutus.rhtml
which renders a partial _contactus.rhtml, I could simply use the
@contactInfo instance var inside _contactsus.rhtml.

So, about doing that, AWDWR on page 125 says:

– In the layout, we have access to the @cart instance variable that
was set by the controller. It turns out that this is also available
inside partials called from the layout. However, this is a bit like
calling a method and passing it some value in a global variable. It
works, but it’s ugly coding, and it increases coupling (which in turn
makes your programs brittle and hard to maintain).

I think for many thing this likely isn’t necessary in practice for
things that are obviously going to be coupled anyway, but I get it. A
view might as well be abstracted the same way any method would be. At
least you’d want that option.

But here’s my problem…

On page 510 the book says:

– Idiomatic Rails developers use a variable named after the template
(article in this instance). In fact, it’s normal to take this a step
further. If the object to be passed to the partial is in a controller
instance variable with the same name as the partial, you can omit the
:object parameter.

OK, so what that says is if I have a controller Company with an action
aboutus and an instance var of @contactInfo (a hash), and I have a view
called aboutus.rhtml which renders a partial _contactInfo.rhtml (same
name as the instance var this time), then the render command can simply
be this:

<%= render :partial => “contactInfo” %>

Instead of having to write this:

<%= render :partial => “contactInfo”, :object => @contactInfo %>

So now we have a partial using the code contactInfo[‘phone’] instead of
@contactInfo[‘phone’].

If you ask me, the fact that we required the instace var to be named
contactInfo, and the partial to be named contactInfo and then the local
variable to be named contactInfo has created a higher degree of
interdependence than if we just used the instance var directly in the
partial.

If I decide to change the instance var name in the controller, that is
going to break the partial code in both cases. If I use the shortcut
idiom and I changethe instance var, then I have to changethe name of the
partial too. Where else might that break. But if I use the instance var
directly in the partial, and changethe ivar name, then all I haveto do
search & replace occurrences of that ivar name. Easy. fast, and fewer
surprises as far as I can tell.

So, what about this convention/idiom according to “the Daves” have I
missed?

– gw

OK, so what that says is if I have a controller Company with an action

<%= render :partial => “contactInfo”, :object => @contactInfo %>
You don’t need to write that. you get that for free with <%=
render :partial => “contactInfo” %> if @contactInfo exists.
You only need it if you’re doing
<%= render :partial => “contactInfo”, :object =>
@someOthercontactInfo %>
partial.
-if you use the ivar in the partial and you change the ivar in the
controller, you have to change the ivar everywhere.
-if you don’t, but you use <%= render :partial => “contactInfo” %>
and you change the ivar, you just have to add :object
-if you don’t and you use <%= render :partial =>
“contactInfo”, :object => @contactInfo %> then you just change the
name there
Change in one place vs change in 23 places

But as far as I’m concerned that’s a relatively modest convenience.
Using the ivar means that you can’t suddenly decide that you’d like
to show a list of companies, since <%= render :partial =>
“contact_nfo”, :collection => @contact_infos %> won’t work. It means
that if that if you need to reuse that partial in some other place,
eg a page where the ‘natural’ instance variable is @company then you
have to create @contact_info = @company.contact_info rather then <%=
render :partial => “contactInfo”, :object => @company.contact_info %>

So yes, there’s a dependance between the name of the partial and the
local variable that is materialised in that partial and there’s one
between the name of the instance variable and the name of the partial
that will just work magically with <%= render :partial =>
“contactInfo” %> but those 2 dependencies are separate. by using the
ivar in the partial you tie both of those together and limit the
reusability of that partial.

Fred

Frederick C. wrote:

OK, so what that says is if I have a controller Company with an action

<%= render :partial => “contactInfo”, :object => @contactInfo %>
You don’t need to write that. you get that for free with <%=
render :partial => “contactInfo” %> if @contactInfo exists.
You only need it if you’re doing
<%= render :partial => “contactInfo”, :object =>
@someOthercontactInfo %>
partial.
-if you use the ivar in the partial and you change the ivar in the
controller, you have to change the ivar everywhere.
-if you don’t, but you use <%= render :partial => “contactInfo” %>
and you change the ivar, you just have to add :object
-if you don’t and you use <%= render :partial =>
“contactInfo”, :object => @contactInfo %> then you just change the
name there
Change in one place vs change in 23 places

But as far as I’m concerned that’s a relatively modest convenience.
Using the ivar means that you can’t suddenly decide that you’d like
to show a list of companies, since <%= render :partial =>
“contact_nfo”, :collection => @contact_infos %> won’t work. It means
that if that if you need to reuse that partial in some other place,
eg a page where the ‘natural’ instance variable is @company then you
have to create @contact_info = @company.contact_info rather then <%=
render :partial => “contactInfo”, :object => @company.contact_info %>

So yes, there’s a dependance between the name of the partial and the
local variable that is materialised in that partial and there’s one
between the name of the instance variable and the name of the partial
that will just work magically with <%= render :partial =>
“contactInfo” %> but those 2 dependencies are separate. by using the
ivar in the partial you tie both of those together and limit the
reusability of that partial.

Thinking about it more, it seems to me the best version is to avoid the
shortcut.

The shortcut makes the ivar, the file name, and the local var in the
partial all dependent on the same name. If I have two controllers
sharing the use of a partial, and each controller & accompanying view
for whatever reason have unique ivar names for the same data that could
be passed to the partial, then the shortcut requires having two partials
of unique names. Partials that draw generic lists comes to mind.

If I declare :object in the render command, then whether I have two
views, or I rename the ivar, the partial file name and internal local
var remain undisturbed. Seems to me that this version does the best job
at preserving the reusability of the partial from the standpoint of
change in the controller and sharing among controllers.

I have no trouble with the abstraction to broaden reuse potential, but
that shortcut version of render seems to ruin it no matter how I look at
it. So, it seems odd that it’s available. Its like someone found himself
typing the same thing over & over in :object and decided a shortcut
would be handy, but it turns out the shortcut ruins the very reusability
goal that he started with. At least, itooks that way to me.

Anyway, I did talk myself into at least using :object and not the ivar
in the partial, but I also figure I’ll avoid “taking it further” with
the shortcut.

– gw

On 10/17/07, Greg W. [email protected] wrote:

makes your programs brittle and hard to maintain).
This is a good point. I don’t recommend using instance variables in
partials. Everything should be passed to the partial from the
template. Treat a partial like a subroutine that can be called in
different contexts and that you pass arguments to.

On page 510 the book says:

– Idiomatic Rails developers use a variable named after the template
(article in this instance). In fact, it’s normal to take this a step
further. If the object to be passed to the partial is in a controller
instance variable with the same name as the partial, you can omit the
:object parameter.

That may be an idiom, but it should be avoided IMO. It’s just a
“shorthand” way of using global variables, which carries all the
negative features of using global variables in general.

Pass everything to partials. Don’t use instance vars in partials at all.

Bob S. wrote:

On 10/17/07, Greg W. [email protected] wrote:

makes your programs brittle and hard to maintain).
This is a good point. I don’t recommend using instance variables in
partials. Everything should be passed to the partial from the
template. Treat a partial like a subroutine that can be called in
different contexts and that you pass arguments to.

So, one last question on this. If a partial requires multiple objects,
is the preferred way to handle that by passing a hash of objects via
:object? Something like this:

render :partial => ‘x’, :object => {‘infoA’ => objectA, ‘infoB’ =>
objectB}

in which case I’d have a local var named x with a hash and could use
x.infoA.someAttr

– gw

Bob S. wrote:

On 10/17/07, Greg W. [email protected] wrote:

So, one last question on this. If a partial requires multiple objects,
is the preferred way to handle that by passing a hash of objects via
:object? Something like this:

render :partial => ‘x’, :object => {‘infoA’ => objectA, ‘infoB’ =>
objectB}

in which case I’d have a local var named x with a hash and could use
x.infoA.someAttr

You can do that, but it would be

x[‘infoA’].someAttr

duh, I knew that :stuck_out_tongue:

Preferred is to pass multiple values using :locals

render :partial => ‘x’, :locals => {:infoA => objectA, :infoB =>
objectB}

Then in the partial, you have reference separate variables:

infoA.someAttr
infoB.someAttr

Perfect, that’s much better. I think I like that even better for a
single object. Using the partial name as the local var bothered me. I
get it, but wasn’t fond of it. I’d much rather have the var name
represent what the object is.

Thx.

– gw

May I use :collection and :locals together to handle parameters while
rendering partial?

Thanks!

On Nov 6, 2007 9:10 PM, eastwoodsz [email protected] wrote:

May I use :collection and :locals together to handle parameters while
rendering partial?

Yes.

On 10/17/07, Greg W. [email protected] wrote:

So, one last question on this. If a partial requires multiple objects,
is the preferred way to handle that by passing a hash of objects via
:object? Something like this:

render :partial => ‘x’, :object => {‘infoA’ => objectA, ‘infoB’ =>
objectB}

in which case I’d have a local var named x with a hash and could use
x.infoA.someAttr

You can do that, but it would be

x[‘infoA’].someAttr

Preferred is to pass multiple values using :locals

render :partial => ‘x’, :locals => {:infoA => objectA, :infoB =>
objectB}

Then in the partial, you have reference separate variables:

infoA.someAttr
infoB.someAttr