ruby-on-rails - شرح - rails معنى



after_commit لسمة (5)

استخدام جوهرة ArTransactionChanges . previous_changes لا يعمل بالنسبة لي في Rails 4.0.x

الاستعمال:

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

أنا أستخدم after_commit في طلبي.

أرغب في تشغيله فقط عند تحديث حقل معين في نموذجي. أي شخص يعرف كيف يفعل ذلك؟


السؤال القديم ولكن لا يزال ينبثق في نتائج البحث.

اعتبارا من القضبان 5 attribute_changed? تم تحطيمها. باستخدام saved_change_to_attribute ؟ بدلا من attribute_changed ؟ موصى به.


لا أعتقد أنه يمكنك القيام بذلك في after_commit

يسمى after_commit بعد أن تم تنفيذ المعاملة المعاملات Rails

على سبيل المثال في بلدي القضبان وحدة التحكم

> 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 

لذلك لن تتمكن من استخدام :if الشرط في after_commit لأنه لن يتم تمييز السمة على أنها تغيرت بعد حفظها. قد تحتاج إلى تتبع ما إذا تم تغيير الحقل الذي أنت بعد changed? في رد اتصال آخر قبل حفظ السجل؟


هذه مشكلة قديمة جدًا ، لكن حل التغييرات previous_changes المقبول ليس قويًا بدرجة كافية. في معاملة 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"=>[...]}

لذلك ، حل بلدي هو:

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://.com/a/20955038
  def track_saved_value(v)
    begin
      v.dup
    rescue TypeError
      v
    end
  end
end

والتي يمكنك تجربتها هنا: github.com/ccmcbeck/after-commit


الإجابة على هذا السؤال القديم لأنه لا يزال يظهر في نتائج البحث

يمكنك استخدام طريقة التغييرات previous_changes التي تُرجع علامة التجزئة للتنسيق:

{"change_attribute" => ["القيمة القديمة" ، "القيمة الجديدة"]}

هذا ما كانت عليه changes حتى يتم حفظ السجل فعليًا (من 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" أو شيء من هذا القبيل





ruby