Posted by
ihower
on
July 23, 2010
According to the decoupling principle, model should do finders by itself, a model should not know too much about associations finders logic.
Bad Smell
class Post < ActiveRecord::Base
has_many :comments
def find_valid_comments
self.comment.find(:all, :conditions => {:is_spam => false},
:limit => 10)
end
end
class Comment < ActiveRecord::Base
belongs_to :post
end
class CommentsController < ApplicationController
def index
@comments = @post.find_valid_comments
end
end
According to the decoupling principle, model should do finders by itself, a model should not know too much about associations finders logic. In here, Post model handle the complex finder of comments, but this is not its job, we should move valid comments finder to the Comment model.
Refactor
class Post < ActiveRecord::Base
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :post
named_scope :only_valid, :conditions => { :is_spam => false }
named_scope :limit, lambda { |size| { :limit => size } }
end
class CommentsController < ApplicationController
def index
@comments = @post.comments.only_valid.limit(10)
end
end
We move the valid comments finder from Post model to Comment model, and make it as named_scope. So the Post and Comment models are loose coupled now and much easier to extend.

Comments
Since comments, only_valid, and limit all return the same ActiveRelation type, there is no violation.
For all classes C. and for all methods M attached to C, all objects to which M sends a message must be instances of classes associated with the following classes:
The argument classes of M (including C).
The instance variable classes of C.
(Objects created by M, or by functions or methods which M calls, and objects in global variables are considered as arguments of M.)
http://www.ccs.neu.edu/research/demeter/papers/law-of-demeter/oopsla88-law-of-demeter.pdf (page 3)