The Dev Blog

Putting Family Management on Rails!

How Far Should the Models Go?

Posted by Guy Naor Mon, 26 Feb 2007 12:01:00 GMT

Recently I had a discussion with some other developers regarding the line separating models and controllers in MVC. The issue is, how much logic should go into the model, and how much in to the controller.

I see many places where the model is left with the CRUD actions only, and maybe a few small things. The rest falls on the hands of the controller.

My preference is to have the business logic pushed as much as possible into the model. Of course there is cross model stuff that must be handled in the controllers (authentication and authorization for example), but the more we push clean login into the model, the less we have to worry about repeating ourselves in the controllers, and the less bugs will be introduced that are not covered by unit tests.

The way I implement it, is that my models have some high level methods that handle complex operations that relate to the model. An example will make it clear. Say we have a content management system, with a content model. The content model has publish_at attribute, and we need to get all the items we need to show, based on this attribute and a count of how many items to show, ordered by the published_at attribute. I'll use rails here, but it applies to any MVC system.

We could write at the controller level:

published_items = Content.find(:all, 
                               :conditions => "published_at < #{Time.now}", 
                               :limit => 15)

Or, the way I prefer it - at the controller we call:

published_items = Content.get_published_items(:items => 15)

And we put the find in the model itself:

class Content < ActiveRecord::Base

  def self.get_published_items(options)
    find(:all, :conditions => "published_at < #{Time.now}", :limit => options[:items])
  end

end

We encapsulate the find and expose the logic. If we now need the published item elsewhere (on a side bar, on an index page) we just call the same model function from other controllers.

Where do you draw the line?

Posted in  | 6 comments

del.icio.us:How Far Should the Models Go? digg:How Far Should the Models Go? spurl:How Far Should the Models Go? wists:How Far Should the Models Go? simpy:How Far Should the Models Go? newsvine:How Far Should the Models Go? blinklist:How Far Should the Models Go? furl:How Far Should the Models Go? reddit:How Far Should the Models Go? fark:How Far Should the Models Go? blogmarks:How Far Should the Models Go? Y!:How Far Should the Models Go? smarking:How Far Should the Models Go? magnolia:How Far Should the Models Go? segnalo:How Far Should the Models Go?

Comments

  1. Debasish Ghosh said about 2 hours later:

    Jamis wrote a blog on Fat Models, Skinny Controllers .. have a look at http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model.

    >
  2. Guy Naor said about 3 hours later:

    Good company to be in ;-)

    I hope more people will "see the light" about it. Some code I see is so controller heavy, it's scary.

  3. Tony Marston said about 19 hours later:

    You know you have got it right when you have produced reusable controllers. If you have a task that does something with TableA, and another task which does the same thing with TableB, then the only difference between those two tasks is the database table that they access. Eveything else is common and should therefore be shared.

    You have a separate model for TableA and TableB, but do you have separate controllers for each of the two tasks? If the answer is "Yes" then you have failed.

  4. Amos King said 1 day later:

    Sometimes it is reasonable to have separate controllers for the tasks, but if you need something that can work on multiple tables you can always place it in the Application Controller?

  5. Guy Naor said 1 day later:

    Tony, well said. And even then it's cleaner to put the logic that relates to the models in them. Encapsulating it for the controller.

    Amos, it's true you can put things in the Application Controller, but the less you put there the better IMO. It could become the catch all for anything you don't know where to put, making it a huge mess. It's sort of like global variables or the session. You do need them, but be mindfull to never abuse them.

  6. Tony Marston said 1 day later:

    Sometimes it is reasonable to have separate controllers for the tasks, <

    Reasonable? In my book it is mandatory. Each task can be broken down into structure, behaviour and content. Structure and behaviour are encapsulated in a library of page controllers, while the content is obtained from one or more database table classes. The page controllers are static and therefore reusable with any database table classes. It is only the database table classes which cotain variable business logic.

    but if you need something that can work on multiple tables you can always place it in the Application Controller? <

    In my book there is no such thing as an application controller. Each page is a self sufficient entity in its own right, therefore each page has its own page controller. In my case I have a small number of static and reusable page controllers, and it is only the number of database table classes (and the business logic which they contain) which is dynamic and variable.

Comments are disabled

Subscribe to The Dev Blog