Decoupling the View from the Model

Hi,

In my views I often find myself doing:

<%= user.login %>

These get scattered all over the application. Now imagine I change the
user's login to name. What happens? It blows in my face. Sure tests can
catch it, but writing tests for that purpose is too painful.

So what kind of tips / ideas / idioms / Design Patterns / other? do you
use to truly decouple the View from the Model.

One should never access object's attributes like this in the view, and
yet we see this in almost all tutorials, books and what have you. It's
now hard for me to get rid of that bad habit, and I don't even know how.

Fernando Perez wrote:

Hi,

In my views I often find myself doing:

<%= user.login %>

These get scattered all over the application. Now imagine I change the
user's login to name. What happens? It blows in my face.

No. Remember that user.login is not an instance variable accessor, even
though it looks like one. It's a method call.
So if you really wanted to, you could do
class User
  def login
    @name
  end
end

Sure tests can
catch it, but writing tests for that purpose is too painful.

You're not writing tests "for that purpose". Rather, you write tests
that exercise as much of your code as possible, then let them tell you
when things break.

[...]

One should never access object's attributes like this in the view,

Says who? Again, this is not really getting the model object's
attributes -- rather, it's calling a method on the model object.
Whether the object happens to have an instance variable with the same
name as the method makes no difference to the view and is an irrelevant
implementation detail.

and
yet we see this in almost all tutorials, books and what have you.

Because there's really no other way to do it, short of assigning every
model method call to a separate controller variable -- and that's just
plain silly.

It's
now hard for me to get rid of that bad habit, and I don't even know how.

Because of Ruby's complete hiding of instance variables, I think it's
not a bad habit. Don't worry about it.

Best,

Because there's really no other way to do it, short of assigning every
model method call to a separate controller variable -- and that's just
plain silly.

No it's not. One way to fix this headache could be to add 1 more layer
to the MVC that get's tied to the model and handles the rendering of an
object. Yeah I know view creeps in the model, but it's in a separate
file to not clutter the true business logic.

Instead of:

<%= user.login %>
<%= user.age %>

We could call:

<%= user.display %>

So that attributes change only in 2 locations (Model and ModelRender)
instead of 100 different places. Does anyone already use such solution?
How does it work out? Is it better or worse than before? I got that idea
for the book Hollub on Patterns. I'm wondering if the 4th layer of MVC
wouldn't get out of control with 200 methods for each view in the app.

There is also another idea using a kind of Presenter Pattern, but I
didn't get it right.

Moreover I figured out that most my views look very similar so finding a
solution to abstract the rendering from the object would be super cool,
and that's where a Presenter could come in handy if used right (I'm not
talking about Django's AutoAdmin!)

Jay Fields has written some articles on his blog about using the
Presenter Pattern with Rails

http://blog.jayfields.com/2006/09/rails-model-view-controller-
presenter.html
http://blog.jayfields.com/2007/01/another-rails-presenter-example.html
http://blog.jayfields.com/2007/02/rails-presenters-additional-layer.html
http://blog.jayfields.com/2007/03/rails-presenter-pattern.html

Michael

That would be a job for either helper methods or partials.

Michael

#!/bin/sh
cd app/views
for file in */*erb; do
  cp $file $file.tmp
  sed -e "s/user\.login/user\.name/g" $file.tmp >$file
  rm $file.tmp
done

Michael Schuerig wrote:

instead of 100 different places.

That would be a job for either helper methods or partials.

Michael

--
Michael Schuerig
mailto:michael@schuerig.de
http://www.schuerig.de/michael/

Sorry, I know I'm still very new to rails but I've been learning quite a
bit and have worked heavily on helpers this week.

don't see this as being tied to that unless the login box was wrapped in
a particular div style or box that is being called on multiple views.
In this case, then yes, absolutely - helpers would be a good thing to
use.

From what I've researched and read, if the helper file contains
non-markup code, it should be moved to the model.

Michael Schuerig wrote:
>> instead of 100 different places.
>
> That would be a job for either helper methods or partials.

From my understanding, helpers were designed for markup with views.

Well, the question *is* about views.

I don't see this as being tied to that unless the login box was
wrapped in a particular div style or box that is being called on
multiple views. In this case, then yes, absolutely - helpers would be
a good thing to use.

From what I've researched and read, if the helper file contains
non-markup code, it should be moved to the model.

If that was the case there ought to be some good reason for it. I don't
see any. Go ahead and use helper methods (and presenters, for that
matter) to extract and bundle common functionality. Don't bother the
model with view concerns.

Michael