我正在尝试生成一个模块,以防止错误地使用update_all
和其他回调忽略方法。
我有一个模块:
module UpdateProtection
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def update_all(updates)
if updates.is_a? Hash
updates.merge!(updated_at: Time.now)
elsif updates.is_a? String
updates = "updated_at = '#{Time.now.utc.strftime('%F %T')}'," + updates
elsif updates.is_a? Array
updates[0] = "updated_at = '#{Time.now.utc.strftime('%F %T')}'," + updates[0]
end
end
end
end
我包含在我希望获得此保护的模型中。我有一个默认范围的模型。如果我打电话:
MyModel.update_all(name: 'foo')
我得到了预期的结果:
SQL (4.1ms) UPDATE `my_models` SET `my_models`.`name` = 'foo', `my_models`.`updated_at` = '2016-09-26 14:46:02' WHERE (my_models.scope_condition is not null)
但是,如果我打电话:
MyModel.unscoped.update_all(name: 'foo')
我明白了:
SQL (4.6ms) UPDATE `my_models` SET `my_models`.`name` = 'foo'
并且未使用我的模块update_all
的实现。
如果我打电话:
MyModel.method(:update_all).source_location
它返回我的模块的路径,而如果我打电话:
MyModel.unscoped.method(:update_all).source_location
它返回:
/home/username/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/activerecord-deprecated_finders-1.0.4/lib/active_record/deprecated_finders/relation.rb
[更新]
在update_all
上调用MyModel.unscoped
时,实际上是在该类方法返回的关系对象上调用它。
我发现了这个解决方案,这有点工作:
Override rails update_all method
但是这会覆盖应用程序中每个模型的update_all,而我只想为特定模型这样做。
Rails / AR版本是4.0.12