views:

149

answers:

2

I have a few objects that are incredibly similar. In fact, they use STI and store all of the data in the same table in the DB. Currently, every time I add a feature or fix a bug, I have to update it in 3 different places, so I would like to DRY my code a little bit. The most common code duplication is in the views. I have seen people using render :template => 'shared/something' to render their common views, the problem is, I have many of these, but only for one particular object (Shipments), so I would prefer something like render :template => 'shipments/shared/something' or render :template => 'abstract_shipments/something'. More importantly though, I would like any of the actual classes to be able to override the template if it needs to.

Do y'all have any suggestions on how to go about this? Thanks very much for any answers!

+1  A: 

The inherit_views plugin might do the job: http://github.com/ianwhite/inherit_views/tree/master. I've used it successfully before.

You could then have a common base controller class for all controllers needing to render shipments and have any common templates in that base controller's views folder with any specific overrides in the individual controllers' views folders.

Shadwell
Thanks, this looks exactly like what I need!
Topher Fangio
A: 

Classes (models at least) don't - or shouldn't - know anything about how they're displayed. That's fundamental to the separation of concerns provided by the MVC pattern.

I think I'd try something like this:

Use a single controller for all the STI models, ShipmentsController or something similar. Apart from it seeming a logical thing to do, all your views will end up in the same place, which ought to help.

As for views, how about a "main" one for the common parts, and one partial for each set of subclass-specific fields? Use a case in your view, or probably more cleanly, a helper method, something like

def partial_name_for_subclass(obj)
  if obj.is_a?(CrudeOilShipment) # or kind_of? or test the type column or use respond_to?
    'crude_oil_shipment'
  # etc
  end
end

DRYer, consider using a convention (Rails loves conventions):

<%= render :partial => @shipment.class.name.downcase, :locals => { :item => @shipment } %>

where you have a partial for each subclass.

Hope some of that helps/makes sense...

Mike Woodhouse