Raylar 3 özelliğin değişip değişmediğini kontrol edin


153

Rails 3'te güncelleme yapmadan önce bir nitelik bloğunun değişip değişmediğini kontrol etmeniz gerekiyor.

street1, street2, şehir, eyalet, posta kodu

Gibi bir şey kullanabileceğimi biliyorum

if @user.street1 != params[:user][:street1]
  then do something....
end

Ancak bu kod parçası GERÇEKTEN uzun olacaktır. Daha temiz bir yol var mı?

Yanıtlar:


282

Check out ActiveModel :: Dirty (varsayılan olarak tüm modellerde mevcuttur). Dokümantasyon gerçekten çok iyi, ancak aşağıdakileri yapmanızı sağlar:

@user.street1_changed? # => true/false

Bir özelliğin bir formda değiştirilip değiştirilmediğini (OP'nin yaptığı gibi görünüyorsa) bu işe yaramaz.
Mark Fraser

8
Elbette öyle. Değerleri params karma değerini kullanarak atarsanız, bunlar formdan gelmiştir.
Peter Brown

şöyle bir şey yapmak istersem: model.collection.changed_size_by? ya da benzeri
Mauro Dias

@MauroDias bunun gibi toplama özelliklerini izlemek için kendi mantığınızı yazmanız gerekir.
Peter Brown

Bunun için bir test kütüphanesi kullanmaya çalışacağım. bir çözüm olabilir, yine de TY
Mauro Dias

54

Birden çok öznitelikteki değişiklikleri kontrol etme sorununu bu şekilde çözdüm.

attrs = ["street1", "street2", "city", "state", "zipcode"]

if (@user.changed & attrs).any?
  then do something....
end

changedYöntemi, nesne için değiştirilebilir niteliklerin bir dizi döner.

Her ikisi de @user.changedve attrsdiziler böylece kavşak alabilirsiniz ( ary & other aryyönteme bakınız ). Kesişimin sonucu bir dizidir. any?Diziyi arayarak , en az bir kavşak varsa doğru olur.

Ayrıca çok yararlı olan changed_attributesyöntem, özniteliklerin bir karmasını orijinal değerleriyle changesdöndürür ve özniteliklerin bir karmasını orijinal ve yeni değerleriyle (bir dizide) döndürür.

APIDock'u bu yöntemleri hangi sürümlerin desteklediğini kontrol edebilirsiniz.

http://apidock.com/rails/ActiveModel/Dirty


1
Bunu yapmanın güzel bir yolu. Tarihsel olarak yaptım if attrs.any?{|attr| @user.send("#{attr}_changed?")}Birkaç farklı özellikten birinin değişip değişmediğini kontrol etmek istediğimde - Tabii ki, bunu sadece kendim tanımladığım attrslerle yapıyorum, çünkü kullanıcı parametrelerini bir sendyönteme atmaktan hoşlanmıyorum . ;)
nzifnab

14

ActiveModel::Dirtybenim için çalışmadı çünkü @model.update_attributes()değişiklikleri sakladı. Yani ben böyle updatebir denetleyicide bir yöntemde değişiklikler tespit :

def update
  @model = Model.find(params[:id])
  detect_changes

  if @model.update_attributes(params[:model])
    do_stuff if attr_changed?
  end
end

private

def detect_changes
  @changed = []
  @changed << :attr if @model.attr != params[:model][:attr]
end

def attr_changed?
  @changed.include :attr
end

Çok fazla özellik değişikliği tespit etmeye çalışıyorsanız, yine de dağınık olabilir. Muhtemelen bunu bir kontrolörde yapmamalıydı, ama meh.


9
Değeri için, bunu previous_changesvarsayılan olarak da kullanılabilir.
Jason Galuten

2
#update_attributesdeğişiklikleri gizlemez. Kaydı kaydeder, böylece model güncellenir ve değişiklik olmaz. Modeldeki alanı değiştirmeniz ve changed?kaydetmeden önce kontrol etmeniz gerekir. yani. @ model.field = 'foo' veya@model.attributes = @model.attributes.merge(params[:model])
Grzegorz

9

Raylar için 5.1+ geri çağrılar

Ruby on Rails 5.1'den itibaren, attribute_changed?ve attribute_wasActiveRecord yöntemleri kullanımdan kaldırılacak

Yerine saved_change_to_attribute?kullanınattribute_changed?

@user.saved_change_to_street1? # => true/false

Burada daha fazla örnek


2

Yukarıdaki cevaplar daha iyi ama yine de bilgi için başka bir yaklaşımımız var, bir nesne için 'katagori' sütun değerini değiştirelim (@design),

@design.changes.has_key?('catagory')

.Changes, sütunun adı olarak anahtar içeren bir karma ve her sütun için iki değer [eski_değer, yeni_değer] içeren bir dizi olarak değerler döndürür. Örneğin, yukarıdaki katagori @design'dan 'ABC'den' XYZ 'olarak değiştirildi,

@design.changes   # => {} 
@design.catagory = 'XYZ'
@design.changes # => { 'catagory' => ['ABC', 'XYZ'] }

Referanslar için ROR değişikliği

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.