如何覆盖模型&的update_all特定型号的关系?

时间:2016-09-26 15:20:58

标签: ruby-on-rails ruby ruby-on-rails-4 rails-activerecord

我正在尝试生成一个模块,以防止错误地使用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

0 个答案:

没有答案