Modelden öznitelik değişiklikleri nasıl tespit edilir?


86

Bir model kaydedildikten sonra çalışan raylarda bir geri arama işlevi oluşturmak istiyorum.

Bu modele sahibim, hak talebinin durumuna bağlı olarak değişen bir "durum" özelliğine sahip talep, olası değerler beklemede, onaylanmış, onaylanmış, reddedilmiş

Veritabanının varsayılan değeri "beklemede" olan "durum" vardır.

Model ilk kez oluşturulduktan veya bir durumdan diğerine güncellendikten sonra, hangi durumdan değiştiğine bağlı olarak belirli görevleri gerçekleştirmek istiyorum.

Benim fikrim modelde bir işleve sahip olmak:

    after_save :check_state

    def check_state
      # if status changed from nil to pending (created)
      do this

      # if status changed from pending to approved
      performthistask
     end

Sorum şu ki, model içindeki değişiklikten önce önceki değeri nasıl kontrol ederim?

Yanıtlar:


173

Sen bakmak gerekir ActiveModel :: Kirli modülü: Sen Talep modeline eylemler aşağıdaki gerçekleştirmek mümkün olmalıdır:

claim.status_changed?  # returns true if 'status' attribute has changed
claim.status_was       # returns the previous value of 'status' attribute
claim.status_change    # => ['old value', 'new value'] returns the old and 
                       # new value for 'status' attribute

claim.name = 'Bob'
claim.changed # => ["name"]
claim.changes # => {"name" => ["Bill", "Bob"]}

Oh! Rails'in sevinci!


6
Bu, model kaydedildikten sonra çalışmayacaktır ki bu da sorduğu şeydir.
Tom Rossi

4
@TomRossi, dirtyaramalar çalışır after_save(hem Rails 2.3 hem de 3.x'te). Birkaç kez kullandım.
Harish Shetty

11
@TomRossi, kirli bayraklar tamamlamadan sonra sıfırlanır, bu nedenle after_commitRails 3.x'te tanıtılan geri aramalarda kullanılamazlar . Kesinlikle çalışacaklar after_save.
Harish Shetty

Hiç bir fikrim yoktu! Kaydedildikten sonra sıfırlanacaklarını sanıyordum!
Tom Rossi

5
@TomRossi Birkaç yıl önce aynı varsayımla başladım. After_save'deki kirli bayrakları kontrol etmeye çalıştığımda işe yaradı. Özünde, ve after_savearasındaki bir durum için bir geri aramadır . Bir istisna atarak tüm işlemi sonlandırabilirsiniz . Mevcut işlemi etkilemeden kaydettikten sonra bir şeyler yapmak istiyorsanız :-)after DMLbefore_commitafter_saveafter_commit
Harish Shetty

38

bunu kullanabilirsin

self.changed

bu kayıtta değişen tüm sütunların bir dizisini döndürür

Ayrıca kullanabilirsin

self.changes

dizi olarak sonuçlardan önce ve sonra değişen sütunların karmasını döndürür


7
self.Bunlarda kullanmanın gereksiz olduğunu söylemek için sadece küçük bir not - sadece changedve diyebilirsiniz changes.
user664833

@ user664833 Daha spesifik olarak, selfmodelin içindeyken atlayabilirsiniz , ancak bunları herhangi bir nesne üzerinde object.changedve ile çağırabilirsiniz object.changes. :)
Joshua Pinter

4

Mevcut durum makinesi eklentilerinden birine göz atmanızı tavsiye ederim:

Her ikisi de durumlar arasında durumları ve geçişleri ayarlamanıza izin verir. Gereksinimlerinizi yerine getirmenin çok kullanışlı ve kolay yolu.


Yakut yanlısı bir deneme yapıyorum. Diyelim ki Claim <ActiveRecord :: Base include AASM aasm_column: status aasm_initial_state: pending aasm_state: pending,: enter =>: enter_pending def enter_pending Notifier.deliver_pending_notification (self) end end Ve veritabanımdaki durum alanım varsayılan değere sahip "beklemede". Durum alanını doldurmadan bir Claim.create yaparsam (böylece 'beklemede' çalışacak), AASM 'enter_pending' yöntemini çalıştırır mı?
David C

2

Rails 5.1+ için, aktif kayıt öznitelik yöntemini kullanmalısınız: Saved_change_to_attribute?

Saved_change_to_attribute? (attr_name, ** seçenekler) '

En son kaydettiğimizde bu özellik değişti mi? Bu yöntem saved_change_to_name?yerine çağrılabilir saved_change_to_attribute?("name"). Benzer şekilde davranır attribute_changed?. Bu yöntem, geri aramalardan sonra kaydetme çağrısının belirli bir özniteliği değiştirip değiştirmediğini belirlemek için kullanışlıdır.

Seçenekler

from Geçildiğinde, bu yöntem, orijinal değer verilen seçeneğe eşit olmadığı sürece yanlış döndürür.

to Geçildiğinde, bu yöntem, değer verilen değere değiştirilmediği sürece yanlış döndürür

Dolayısıyla, öznitelik değerindeki değişikliğe dayalı bir yöntem çağırmak isterseniz modeliniz şöyle görünecektir:

class Claim < ApplicationRecord
  
  after_save :do_this, if: Proc.new { saved_change_to_status?(from: nil, to: 'pending') }

  after_save :do_that, if: Proc.new { saved_change_to_status?(from: 'pending', to: 'approved') }

  
  def do_this
    ..
    ..
  end

  def do_that
    ..
    ..
  end

end

Geri aramada değer değişikliğini kontrol etmek istemiyorsanız, aşağıdakileri yapabilirsiniz:

class Claim < ApplicationRecord

  after_save: :do_this, if: saved_change_to_status?


  def do_this
    ..
    ..
  end

end

0

Sorunun birçok yerde yükseldiğini gördüm, bu yüzden kodu biraz daha güzel hale getirmek için (ve her yerde bir milyon if / else ifadesinden kaçınmak için) küçük bir rubygem yazdım: https://github.com/ronna-s / on_change . Umarım bu yardımcı olur.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.