Rails Models: Fat, Not Obese


“Fat models, skinny controllers” is a mantra in the Rails community, with good reason: It produces better code. Move the complicated business logic into the model, make the model “smart”, and let the controller just take care of managing traffic. And don’t forget “no logic in the view”!

I have seen this advice misused however, mostly by taking it too far. For example, the carrierwave gem (which is awesome in general) adds a method to the Uploader model class of [version]_url. Cool, the model knows its own URL! And arguably, since the gem puts the files in a predictable location under the public directory, this is something the gem can encapsulate.

However, I’m not convinced that a model should know its URL. Yes, this model is fatter & smarter, but it also breaks down the important wall between a model which can run anywhere (and isn’t necessarily tied to a browser implementation) and the web view/controller combination that is serving the content.

Another example (changed to protect the relatively innocent, but you’ll get the idea): Models frequently have a method like “name” defined, which might be something as simple as “#{first_name} #{last_name}”. Fair enough. The model knows that its name is a concatenation of first and last.

How about this though?

def author_byline
“Written by #{name}”

Cool, right? The model knows its own byline! Again, someone thought that if fat was good, obese was better. This code is not tied to the model, but to how it is represented in a view. This code belongs in a helper.

If you are trying to decide where code belongs, here are reasonable guidelines:

– If the code makes sense in a unit test running on a command line without a browser, put it in the model.
– If the code is related to how urls are built, add a route that takes the model as a parameter and generates a proper url.
– If the code reflects how the model is represented on a web page, put it in a view, and if it appears multiple times and you want to make it more DRY, move it to a helper.
– Any logic tied specifically to the http implementation should go in the controller.

Good luck, hope this is helpful!

Leave a Comment