当我使用类方法修补ActiveRecord :: Base时,这些方法由不同的模型ActiveRecord_Relation类(如User :: ActiveRecord_Relation)继承,并且可以在特定活动记录关系的实例上调用。但是,在为原始模型进行活动记录调用时,这会导致一些意外行为。
这是一个微不足道的例子:
User.count
=> 3544
users = User.where("created_at > ?", 1.month.ago)
users.count
=> 174
class ActiveRecord::Base
def self.monkey_foo(options = {}, &block)
User.count
end
end
User.monkey_foo
=> 3544
Book.monkey_foo # Another model
=> 3544
users.monkey_foo
=> 173 # This is the count of the users relation, not the User model
Book.where("created_at > 1.year.ago").monkey_foo
=> 3544 # Issue only affects User model relations
导致此行为的原因是什么?
我知道像这样的猴子修补对于任何严肃的事情都是一个非常糟糕的主意。我不小心发现了这种行为,我非常好奇地知道它为什么会发生。
答案 0 :(得分:2)
这个问题的关键在delegation.rb
基本上,这种方法缺少关于Relation的实现(为了简洁而略微简化)
def method_missing(method,*args,&block)
scoping { @klass.public_send(method, *args, &block) }
end
(@ klass是该关系所属的活动记录类)
范围方法设定班级'阻止持续时间current_scope
。这包含where子句,排序等等。这使得您可以在关系上调用类方法,并让这些类方法在关系定义的范围内运行。
在本书案例中,这种情况仍然存在,但是确定范围发生在Book,但查询是针对用户的,因此范围不会改变结果。