Rails:覆盖ActiveRecord关联方法

时间:2010-05-23 05:36:57

标签: ruby-on-rails ruby activerecord override

有没有办法覆盖ActiveRecord关联提供的其中一种方法?

比如说我有以下典型的多态性has_many:通过关联:

class Story < ActiveRecord::Base
    has_many :taggings, :as => :taggable
    has_many :tags, :through => :taggings, :order => :name
end


class Tag < ActiveRecord::Base
    has_many :taggings, :dependent => :destroy
    has_many :stories, :through => :taggings, :source => :taggable, :source_type => "Story"
end

您可能知道这会为Story模型添加一大堆相关方法,例如标签,标签&lt;&lt;,tags =,tags.empty?等。

如何覆盖其中一种方法?具体而言,标签&lt;&lt;方法。覆盖普通的类方法很容易,但我似乎无法找到有关如何覆盖关联方法的任何信息。做点什么

def tags<< *new_tags
    #do stuff
end

在调用时会产生语法错误,所以显然不那么简单。

7 个答案:

答案 0 :(得分:55)

您可以使用has_many块来扩展与方法的关联。请参阅注释“使用块来扩展关联”here 覆盖现有方法也有效,但不知道这是否是一个好主意。

  has_many :tags, :through => :taggings, :order => :name do
    def << (value)
      "overriden" #your code here
      super value
    end     
  end

答案 1 :(得分:18)

如果要在Rails 3.2中访问模型本身,则应使用proxy_association.owner

示例:

class Author < ActiveRecord::Base
  has_many :books do
    def << (book)
      proxy_association.owner.add_book(book)
    end
  end

  def add_book (book)
    # do your thing here.
  end
end

请参阅documentation

答案 2 :(得分:0)

我认为您需要def tags.<<(*new_tags)作为签名,这应该有效,或者如果您需要覆盖多个方法,则需要使用以下相同的内容。

class << tags
  def <<(*new_tags)
    # rawr!
  end
end

答案 3 :(得分:0)

您必须定义tags方法以返回具有<<方法的对象。

你可以这样做,但我真的不推荐它。除了尝试替换ActiveRecord使用的东西之外,只需向模型添加一个方法就可以做得更好。

这基本上运行默认的tags方法添加&lt;&lt;生成对象的方法并返回该对象。这可能有点资源,因为每次运行它都会创建一个新方法

def tags_with_append
  collection = tags_without_append
  def collection.<< (*arguments)
    ...
  end
  collection
end
# defines the method 'tags' by aliasing 'tags_with_append'
alias_method_chain :tags, :append  

答案 4 :(得分:0)

我使用的方法是扩展关联。您可以在此处查看我处理“数量”属性的方式:https://gist.github.com/1399762

它基本上允许你做

has_many : tags, :through => : taggings, extend => QuantityAssociation

如果你可以做同样的事情,不知道你希望通过覆盖方法来实现什么,很难知道。

答案 5 :(得分:0)

这可能对您的情况没有帮助,但对于其他人来说可能会有用。

协会回调: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

文档示例:

class Project
  has_and_belongs_to_many :developers, :after_add => :evaluate_velocity

  def evaluate_velocity(developer)
    ...
  end
end

另见Association Uptensions:

class Account < ActiveRecord::Base
  has_many :people do
    def find_or_create_by_name(name)
      first_name, last_name = name.split(" ", 2)
      find_or_create_by_first_name_and_last_name(first_name, last_name)
    end
  end
end

person = Account.first.people.find_or_create_by_name("David Heinemeier Hansson")
person.first_name # => "David"
person.last_name  # => "Heinemeier Hansson"

答案 6 :(得分:0)

Rails guides直接覆盖添加方法的文档。

OP覆盖<<的问题可能是唯一的例外,关注the top answer。但它不适用于has_one的{​​{1}}分配方法或getter方法。