---
title: Skinny controllers, skinny models in Rails
teaser: Does a simple controller mean a complex model in Rails development?
tags: web,rails
author: Joe Ferris
published_on: 2008-05-01
---

I hear a lot of people recommending the skinny controller, fat model approach to
Rails development. I'm all for keeping controllers simple, but what happens if
you keep moving logic into your models? If your editor slows down while loading
up your model files, maybe it's time for a new approach.

Let's say you have an application that needs to handle <abbr title="Portable
Document Format">PDF</abbr> documents. You have a very simple Document model to
keep track of them:

```ruby
class Document < ActiveRecord::Base
  validates_presence_of :title
  has_attached_file :pdf
  validates_attachment_presence :pdf
end
```

But after your application has been live for a few days, it becomes clear that
you need to provide a way to view these documents online, and your client's
weapon of choice is <abbr title="HyperText Markup Language">HTML</abbr>. So, you
add a method to convert your PDFs to <abbr title="HyperText Markup
Language">HTML</abbr> documents:

```ruby
class Document < ActiveRecord::Base

  # ...

  def convert_to_html
    # ...some fancy magic...
  end

  def converted_to_html?
    File.exist?(html_file_path)
  end

  def html_file_path
    File.join(HTML_STORAGE_DIR, pdf.original_filename + '.html')
  end

  # probably a few more methods...

end
```

Everything is working great, but now you have to look through all this <abbr
title="HyperText Markup Language">HTML</abbr> junk whenever you're working on
Document. Worse, the tests for <abbr title="HyperText Markup
Language">HTML</abbr> conversion and documents are all mixed up. A very common
and simple technique can save us from this mess: composition.

For some reason, many Rails developers seem to avoid using model classes that
are not stored in the database. This leads to shoving too much key functionality
into one of your key models, which of course leads to complex, incomprehensible
model files and tests. I see no reason for an <abbr title="HyperText Markup
Language">HTML</abbr> file to have its own, separate entry in the database, but
it certainly has enough behavior to warrant its own class. Let's pull that
functionality into an HtmlFile class:

```ruby
class HtmlFile

  attr_reader :source_path

  def initialize (source_path)
    @source_path = source_path
  end

  def name
    @name ||= File.basename(source_path) + '.html'
  end

  def generate
    # ...some magic with file.path here...
    self
  end

  def path
    @path ||= File.join(HTML_STORAGE_DIR, name)
  end

  def exists?
    File.exist?(path)
  end

  # ... some other useful methods ...

end
````

Simplicity reigns again! But if they aren't ActiveRecord classes, how do you
join these models together? Good, old-fashioned composition:

```ruby
class Document

  # ...

  def html_file
    @html_file ||= HtmlFile.new(pdf.original_filename)
  end

  def convert_to_html
    @html_file = HtmlFile.new(pdf.original_filename).generate
  end

end
```

Here's a tip: if you find yourself organizing your model files into separate,
commented sections, maybe you have a new model waiting to be born.

If you're facing similar challenges in your Rails project and need expert help, thoughtbot is here to assist. Let's discuss how we can help you build maintainable and scalable applications – [Contact us](https://thoughtbot.com/hire-us).
