开发者

Extending Active Record to reduce redundancy

Suppose I have two classes in a Rails application:

class Subject < ActiveRecord::Base  
  def children?
    Subject.where(:parent_id => self.id).length > 0
  end

 def children
   Subject.where(:parent_id => self.id)
 end 
end


class Region < ActiveRecord::Base  
  def children?
    Region.where(:parent_id => self.id).length > 0
  end

 def children
   Region.where(:parent_id => self.id)
 end 
end

What would be the best way to reduce the redundant class methods? Would I extend ActiveRecord with two new methods? If so, how could I wri开发者_JAVA百科te those two new methods to be available for both classes?

Thanks, Mike


Actually what are you dealing with is has_many association.

DRY principle is very good one, but not for this case. You want to extract very simple and native stuff out off model, while it will complicate main picture.

So you can just refactor a little

class Subject < ActiveRecord::Base
  has_many :children, :class_name => "Subject", :foreign_key => :parent_id

  def children?
    children.present?
  end
end


Have a look at acts_as_tree to see what it does or use it as it looks like you are trying to perform the same tasks.


if you are dealing with small objects a quick fix is to create 2 generic methods in your application helper file:

def children?(myObject)
  myObject.where(:parent_id => myObject.id).length > 0
end
def children(myObject)
  myObject.where(:parent_id => myObject.id)
end 

Edit: for anything more resource intensive you can define a method in ActiveRecord::Base since they both inherit from it.

def children?
  self.where(:parent_id => self.id).length > 0
end
def children
  self.where(:parent_id => self.id)
end


I agree with @abdollar's suggestion for using acts_as_tree. Or you could just create an association onto the same table (which is what acts_as_tree does).

If you wanted to roll your own using those methods you've given as examples, you could create a module in lib which you can require and include in your models...

# lib/children.rb
module Children
  def children
    self.class.where(:parent_id => self.id)
  end

  def children?
    children.present?
  end
end

# app/models/subject.rb (or any other model)
require 'children'
class Subject < ActiveRecord::Base
  include Children
end

If you're using rails 2, you won't need to do require 'children' since lib is autoloaded. If you're using rails 3, you could put that into an initializer or something to clean it up.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜