重写ActiveRecord的find
的正确方法是什么,以使其在模型类(如Comment.find(1)
)和集合(如post.comments.find(1)
)上使用时具有相同的行为?
让我们以这两个简单的模型为例:
class Post < ApplicationRecord
has_many :comments
end
class Comment < ApplicationRecord
belongs_to :post
def self.find(*args)
puts 'Overridden find called!'
super
end
end
对于这样的类,Comment.find(1)
正确使用了重写方法,但是post.comments.find(1)
仍使用find
的原始版本。
我知道我可以在#find
中覆盖ActiveRecord::Associations::CollectionProxy
,但是我不喜欢这种解决方案,因为它会影响应用程序中的每个模型。您能提出正确的解决方案吗?
编辑: 我想要实现的是:
Comment.find(1) # prints 'Overridden find called'
some_post.comments.find(1) # prints 'Overridden find called'
Post.find(1) # does NOT print 'Overridden find called', calls regular find
答案 0 :(得分:3)
由于CollectionProxy
在find
上调用了CollectionAssociation
,随后又调用了scope.find
,因此您不需要做任何花哨的操作来覆盖:
module CustomFinder
def find
puts "I'm noisy!"
super
end
end
class Post < ApplicationRecord
extend CustomFinder
has_many :comments
end
class Comment < ApplicationRecord
extend CustomFinder
belongs_to :post
end
或者,如果您要做在每个模型上都想要这样做:
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
extend CustomFinder
end
将来,您可以使用foo.method(:find).source_location
,然后在Github上查看相关代码,以更好地了解幕后情况,而不会浪费很多时间在黑暗中摸索。
有关如何执行此操作的另一个示例,check out the way Friendly ID handles it。