[英]Rails: Overriding ActiveRecord association method
Is there a way to override one of the methods provided by an ActiveRecord association? 有没有办法覆盖ActiveRecord关联提供的方法之一?
Say for example I have the following typical polymorphic has_many :through association: 比如说我有以下典型的多态has_many:through关联:
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
As you probably know this adds a whole slew of associated methods to the Story model like tags, tags<<, tags=, tags.empty?, etc. 您可能知道,这会将整个关联方法添加到Story模型中,例如标签,标签<<,标签=,tags.empty?等。
How do I go about overriding one of these methods? 我该如何覆盖这些方法之一? Specifically the tags<< method.
特别是tags <<方法。 It's pretty easy to override a normal class methods but I can't seem to find any information on how to override association methods.
重写普通的类方法很容易,但是我似乎找不到有关如何重写关联方法的任何信息。 Doing something like
做类似的事情
def tags<< *new_tags
#do stuff
end
produces a syntax error when it's called so it's obviously not that simple. 调用时会产生语法错误,因此显然不是那么简单。
You can use block with has_many
to extend your association with methods. 您可以在
has_many
使用block来扩展与方法的关联。 See comment "Use a block to extend your associations" here . 请参见此处的注释“使用块扩展您的关联”。
Overriding existing methods also works, don't know whether it is a good idea however. 覆盖现有方法也可以,但是不知道这是否是一个好主意。
has_many :tags, :through => :taggings, :order => :name do
def << (value)
"overriden" #your code here
super value
end
end
If you want to access the model itself in Rails 3.2 you should use proxy_association.owner
如果要在Rails 3.2中访问模型本身,则应使用
proxy_association.owner
Example: 例:
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
See documentation 参阅文件
This may not be helpful in your case but could be useful for others looking into this. 这可能对您的情况没有帮助,但可能对其他调查此问题的人有用。
Association Callbacks: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html 关联回调: http : //api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
Example from the docs: 来自文档的示例:
class Project
has_and_belongs_to_many :developers, :after_add => :evaluate_velocity
def evaluate_velocity(developer)
...
end
end
Also see Association Extensions: 另请参阅关联扩展:
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"
I think you wanted def tags.<<(*new_tags)
for the signature, which should work, or the following which is equivalent and a bit cleaner if you need to override multiple methods. 我认为您需要
def tags.<<(*new_tags)
作为签名,应该可以工作,或者以下等价的工作,如果您需要覆盖多个方法,则可以更干净一些。
class << tags
def <<(*new_tags)
# rawr!
end
end
You would have to define the tags method to return an object which has a <<
method. 您将必须定义标签方法以返回具有
<<
方法的对象。
You could do it like this, but I really wouldn't recommend it. 您可以这样做,但是我真的不建议这样做。 You'd be much better off just adding a method to your model that does what you want than trying to replace something ActiveRecord uses.
与向模型中添加ActiveRecord所使用的方法相比,向模型中添加一种可以执行所需操作的方法要好得多。
This essentially runs the default tags
method adds a << method to the resulting object and returns that object. 这实际上是运行默认的
tags
方法,将<<方法添加到结果对象,然后返回该对象。 This may be a bit resource intensive because it creates a new method every time you run it 这可能会占用一些资源,因为每次运行它都会创建一个新方法
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
Rails guides documents about overriding the added methods directly. Rails指导有关直接覆盖添加的方法的文档。
OP's issue with overriding <<
probably is the only exception to this, for which follow the top answer . OP的优先级
<<
可能是唯一的例外,为此,遵循最高答案 。 But it wouldn't work for has_one
's =
assignment method or getter methods. 但是对于
has_one
的=
赋值方法或getter方法不起作用。
The method I use is to extend the association. 我使用的方法是扩展关联。 You can see the way I handle 'quantity' attributes here: https://gist.github.com/1399762
您可以在此处查看我处理“数量”属性的方式: https : //gist.github.com/1399762
It basically allows you to just do 它基本上可以让你做
has_many : tags, :through => : taggings, extend => QuantityAssociation
Without knowing exactly what your hoping to achieve by overriding the methods its difficult to know if you could do the same. 如果不确切地知道您希望通过覆盖这些方法实现什么,那么很难知道您是否可以这样做。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.