Rails: Organizing Models by Attribute
One of the Ruby on Rails apps that I work on has a few models that have lots of stuff in them. The Company
model in this app is 311 lines long. Now, I know that won't break any records – theUser
model in Discourse is 906 lines long – but it's long enough to keep you from holding the whole thing in your head at once. As a result, I've changed the way I organize all the attribute logic in my models.
In all the Rails tutorials, you will see models organized something like this:
class Company < ActiveRecord::Base
attr_accessible :name, :billing_address_id, :shipping_address_id,
:industry_id, :salesperson_id, :price_level_id
validates :name, :billing_address, :shipping_address,
:industry, :salesperson, :price_level, presence: true
validates :name, uniqueness: true
belongs_to :billing_address, class: "Address"
# And so on
end
I think this is just wrong.
All the logic related to a single attribute is spread out across the entire model. If you want to know what the name
attribute is all about, you have to look in three different places, which means it's easy to miss something. You can get away with this when a model is small, but it's simply unworkable as a model grows larger than the height of your screen. Here's how I would rewrite this model:
class Company < ActiveRecord::Base
attr_accessible :name
validates :name, presence: true, uniqueness: true
attr_accessible :status
validates :status, presence: true
attr_accessible :billing_address_id
belongs_to :billing_address, class: "Address"
validates :billing_address
# And so on
end
This is functionally equivalent to the first example, but it's easy to immediately grasp everything there is to know about the name
attribute – because it's all there on those first two lines and nowhere else. The only drawback is that this approach results in even longer model files (since each attr_accessible
and validates_presence_of
macro gets its own line), but so what?
Do you really want to be reading the scribblings of a madman? Because that's what the first approach is.