有没有办法覆盖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
在调用时会产生语法错误,所以显然不那么简单。
答案 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
答案 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方法。