Jalankan callback hanya jika atribut telah berubah di Rails

100

Saya memiliki asosiasi berikut di aplikasi saya:

# Page 
belongs_to :status

Saya ingin menjalankan panggilan balik kapan pun status_iddari a pagetelah berubah.

Jadi, jika page.status_idpergi dari 4 ke 5, saya ingin bisa menangkapnya.

Bagaimana melakukannya?

Hommer Smith
sumber

Jawaban:

209

Rel 5.1+

class Page < ActiveRecord::Base
  before_save :do_something, if: :will_save_change_to_status_id?

  private

  def do_something
    # ...
  end
end

Komit yang mengubah ActiveRecord :: Dirty ada di sini: https://github.com/rails/rails/commit/16ae3db5a5c6a08383b974ae6c96faac5b4a3c81

Berikut adalah entri blog tentang perubahan ini: https://www.ombulabs.com/blog/rails/upgrades/active-record-5-1-api-changes.html

Berikut adalah ringkasan yang saya buat untuk diri saya sendiri tentang perubahan pada ActiveRecord :: Dirty in Rails 5.1+:

ActiveRecord :: Kotor

https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Dirty.html

Sebelum Menyimpan (PERUBAHAN OPSIONAL)

Setelah memodifikasi objek dan sebelum menyimpan ke database, atau di dalam before_savefilter:

  • changes seharusnya sekarang changes_to_save
  • changed? seharusnya sekarang has_changes_to_save?
  • changed seharusnya sekarang changed_attribute_names_to_save
  • <attribute>_change seharusnya sekarang <attribute>_change_to_be_saved
  • <attribute>_changed? seharusnya sekarang will_save_change_to_<attribute>?
  • <attribute>_was seharusnya sekarang <attribute>_in_database

Setelah Menyimpan (BREAKING CHANGE)

Setelah memodifikasi objek dan setelah menyimpan ke database, atau di dalam after_savefilter:

  • saved_changes(menggantikan previous_changes)
  • saved_changes?
  • saved_change_to_<attribute>
  • saved_change_to_<attribute>?
  • <attribute>_before_last_save

Rel <= 5.0

class Page < ActiveRecord::Base
  before_save :do_something, if: :status_id_changed?

  private

  def do_something
    # ...
  end
end

Ini memanfaatkan fakta bahwa before_savecallback dapat dieksekusi secara bersyarat berdasarkan nilai kembalian dari panggilan metode. The status_id_changed?Metode berasal dari ActiveModel :: Kotor , yang memungkinkan kita untuk memeriksa apakah atribut tertentu telah berubah dengan hanya menambahkan _changed?untuk nama atribut.

Kapan do_somethingmetode harus dipanggil sesuai dengan kebutuhan Anda. Bisa jadi before_saveatau after_savesalah satu dari ActiveRecord :: Callbacks yang ditentukan .

pdobb
sumber
4
Solusi ini tidak digunakan lagi di versi yang lebih baru.
Mateus Luiz
6
Diperbarui dengan info Rails 5.1+.
pdobb
16

Ini attribute_changed?tidak digunakan lagi di Rails 5.1, sekarang gunakan saja will_save_change_to_attribute?.

Untuk informasi lebih lanjut, lihat masalah ini .

Mateus Luiz
sumber