While working on Ignitious, I wrote some code that looked something like this:

class Commit < ActiveRecord::Base
  has_many :files, :class_name => 'CommitFile'
  has_many :added_files, :class_name => 'CommitFile', :conditions => {:state => 'added'}
  has_many :removed_files, :class_name => 'CommitFile', :conditions => {:state => 'removed'}
  has_many :modified_files, :class_name => 'CommitFile', :conditions => {:state => 'modified'}
end

class CommitFile < ActiveRecord::Base
  belongs_to :commit
end

'Created new records like this:'
Commit.files.create(:name => 'foo', :state => 'added')

Then I realized, using named scopes, I could move all state logic into the CommitFile class like so:

class Commit < ActiveRecord::Base
  has_many :files, :class_name => 'CommitFile'
end

class CommitFile < ActiveRecord::Base
  belongs_to :commit
  named_scope :added, :conditions => {:state => 'added'}, :order => 'filename'
  named_scope :removed, :conditions => {:state => 'removed'}, :order => 'filename'
  named_scope :modified, :conditions => {:state => 'modified'}, :order => 'filename'
end

'Create new records like this:'
Commit.files.added.new(:name => 'foo')

That’s it! The Commit class no longer cares about the implementation of the status logic. It’s a subtle change, but one that I think will help with future refactorings.

Share and Enjoy:
  • Print this article!
  • Digg
  • Facebook
  • Tumblr
  • Twitter

3 Comments

  1. Andy Maleh says:

    Nice illustration for the difference between the two approaches: has_many and named_scope.

  2. Matt Polito says:

    Also it’s probably more efficient in that the named scope is not adding a bunch of methods and associations that the has_many would. You could probably even add a default scope in there and get rid of all those order statements.

Leave Your Reply

:D :) :o :eek: :( :lol: :wink: :arrow: :idea: :?: :!: :evil: :p