after_commit为一个属性

我在我的应用程序中使用after_commit。

我希望它只能在我的模型中更新特定的字段时触发。 任何人都知道如何做到这一点?

老问题,但这是我发现,可能与after_commitcallback(closurespaukul的答案 )的一种方法。 至less,这两个值都在IRB中的后提交中持续存在。

after_commit :callback, if: proc { |record| record.previous_changes.key?(:attribute) && record.previous_changes[:attribute].first != record.previous_changes[:attribute].last } 

回答这个老问题,因为它仍然在search结果中popup

你可以使用返回hash格式的previous_changes方法:

{“changed_attribute”=> [“旧值”,“新值”]}

直到logging被保存起来(从active_record / attribute_methods / dirty.rb),这是什么变化 :

  def save(*) #:nodoc: if status = super @previously_changed = changes @changed_attributes.clear # .... whatever goes here 

所以在你的情况下,你可以检查previous_changes.key? "your_attribute" previous_changes.key? "your_attribute"或类似的东西

我不认为你可以在after_commit做到这after_commit

在事务被提交Rails事务之后调用after_commit

例如在我的轨道控制台

 > record = MyModel.find(1) => #<MyModel id: 1, label: "test", created_at: "2011-08-19 22:57:54", updated_at: "2011-08-19 22:57:54"> > record.label = "Changing text" => "Changing text" > record.label_changed? => true > record.save => true > record.label_changed? => false 

因此,您将无法使用after_commit :if条件,因为该属性不会因为已保存而被标记为已更改。 你可能需要跟踪你之后的领域是否changed? 在另一个callback之前保存logging?

这听起来像你想要的东西像条件callback 。 如果你已经发布了一些代码,我可以指出你在正确的方向,但我想你会想要使用这样的东西:

 after_commit :callback, :if => Proc.new { |record| record.field_modified? } 

这是一个非常古老的问题,但是接受的previous_changes解决scheme不够强大。 在ActiveRecord事务中,有两个原因可以保存模型。 previous_changes只反映最终save的结果。 考虑这个例子

 class Test < ActiveRecord::Base after_commit: :after_commit_test def :after_commit_test puts previous_changes.inspect end end test = Test.create(number: 1, title: "1") test = Test.find(test.id) # to initialize a fresh object test.transaction do test.update(number: 2) test.update(title: "2") end 

其输出:

 {"title"=>["1", "2"], "updated_at"=>[...]} 

但是,你需要的是:

 {"title"=>["1", "2"], "number"=>[1, 2], "updated_at"=>[...]} 

所以,我的解决scheme是这样的:

 module TrackSavedChanges extend ActiveSupport::Concern included do # expose the details if consumer wants to do more attr_reader :saved_changes_history, :saved_changes_unfiltered after_initialize :reset_saved_changes after_save :track_saved_changes end # on initalize, but useful for fine grain control def reset_saved_changes @saved_changes_unfiltered = {} @saved_changes_history = [] end # filter out any changes that result in the original value def saved_changes @saved_changes_unfiltered.reject { |k,v| v[0] == v[1] } end private # on save def track_saved_changes # maintain an array of ActiveModel::Dirty.changes @saved_changes_history << changes.dup # accumulate the most recent changes @saved_changes_history.last.each_pair { |k, v| track_saved_change k, v } end # v is an an array of [prev, current] def track_saved_change(k, v) if @saved_changes_unfiltered.key? k @saved_changes_unfiltered[k][1] = track_saved_value v[1] else @saved_changes_unfiltered[k] = v.dup end end # type safe dup inspred by http://stackoverflow.com/a/20955038 def track_saved_value(v) begin v.dup rescue TypeError v end end end 

你可以在这里试试: https : //github.com/ccmcbeck/after-commit

使用gemArTransactionChanges 。 Rails 4.0.x中的previous_changes不适合我

用法:

 class User < ActiveRecord::Base include ArTransactionChanges after_commit :print_transaction_changes def print_transaction_changes transaction_changed_attributes.each do |name, old_value| puts "attribute #{name}: #{old_value.inspect} -> #{send(name).inspect}" end end end