On 18 Apr 2009, at 23:08, Lenny Marks wrote:
On Apr 18, 2009, at 1:17 PM, Fernando Perez wrote:
Hi,
Let's take the example of the depot app. In my controller I set
@order.
Then in the view comes the bad stuff:
@order.items.each do |item|
item.product.title
end
Now I'm having problems specing item.product.title. A quick and dirty
fix is to trade a for for an underscore, so I create
Item#product_title:
def product_title
product.title
end
The problem is that I have a few models that act the same way, so I
would find myself writing lot's of these little instance methods, and
the solution looks a bit stupid to me. So how do you handle such
issue?
The risk you've identified here is that your views are coupled to the
relationship between an order and the title of the products that make
up that order. If you were coding down in your model layer and decided
to make a change to the structure of your models then code far, far,
away in the views would break. In a small application like a blog,
this might not be a problem, but as your codebase starts to get
bigger, it's a worry you want to avoid.
Putting on your 'outside-in' hat and thinking about *what the view
wants*, you could code the view, which doesn't need or want to care
about the structure of these models, more like this:
@order.product_titles do |product_title|
<%= product_title %>
end
Now you're going to need to add this Order#product_titles method to
your model layer. Having this extra method buys you more
maintainability in the future: the structure of the model objects is
hidden from the views, and if you need to change that structure, the
code you'll need to change to keep the views working
(Order#product_titles) is right down there next to you in the model
layer where you're working. This sort of cohesion - keeping the things
that change together in the same part of the codebase, makes
maintenance much easier and less accident-prone.
By designing a custom protocol (think 'API') on your model layer for
the use by the views, rather than constraining yourself to the ones
that come out of the box with ActiveRecord, you're putting some
lubrication in between the layers, making it easier for them to move
independently.
The trade-off, obviously, is that you're adding extra methods to your
models. If you imagine doing this for every view on a large project,
you might end up with quite a bit of clutter on those models. This is
where you could consider adding another 'facade' layer that wraps the
models and presents them to the views in the appropriate manner. At
Songkick, we use a presenter layer for this purpose, and it works very
nicely.
Matt Wynne
http://blog.mattwynne.net
http://www.songkick.com
_______________________________________________
rspec-users mailing list
rspec-users@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users