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

Reply via email to