Bir kaydın yeni kaydetme sonrasında oluşturulup oluşturulmadığını veya güncellendiğini belirleme


98

#New_record? işlevi, bir kaydın kaydedilip kaydedilmediğini belirler. Ama after_savekancada her zaman yanlıştır . Kaydın yeni oluşturulmuş bir kayıt mı yoksa güncellemeden eski bir kayıt mı olduğunu belirlemenin bir yolu var mı?

before_createModelde bir bayrak ayarlamak veya db'ye başka bir sorgu gerektirmek gibi başka bir geri arama kullanmamayı umuyorum .

Herhangi bir tavsiye takdir edilmektedir.

Düzenleme: Olasılığı belirlemem gerekiyor after_saveve benim özel kullanım durumum için zaman damgası yok updated_atveya yokupdated_on


1
hmm belki de bir before_save'de bir param geçirebilir? sadece yüksek sesle düşünüyorum
Yolculuk

Yanıtlar:


170

Bunu bir after_savegeri arama için kullanmayı düşünüyordum .

Daha basit bir çözüm kullanmaktır id_changed?(değişmeyeceği için update) veya created_at_changed?zaman damgası sütunları mevcut olsa bile .

Güncelleme: @mitsy'nin işaret ettiği gibi, bu kontrol geri aramaların dışında gerekliyse kullanın id_previously_changed?. Belgelere bakın .



6
Bir after_update ve bir after_create ile ayırt etmek en iyisidir. Geri çağırmalar, bunun bir oluşturma veya güncelleme olup olmadığını göstermek için bir bağımsız değişken alan ortak bir yöntemi paylaşabilir.
matthuhiggins

2
Bu değişmiş olabilir. En azından Rails 4'te after_save geri araması after_create veya after_update geri aramasından sonra çalışır (bkz. Guides.rubyonrails.org/active_record_callbacks.html ).
Mark

3
Bu alanların hiçbirinin kontrol edilmesi dışında çalışmaz after_save.
fatuhoku

3
id_changed?kayıt kaydedildikten sonra yanlış olacaktır (en azından kancaların dışında). Bu durumda,id_previously_changed?
mltsy

31

Burada bildiğim raylar büyüsü yok, bunu kendin yapmak zorundasın. Bunu sanal bir öznitelik kullanarak temizleyebilirsiniz ...

Model sınıfınızda:

def before_save
  @was_a_new_record = new_record?
  return true
end

def after_save
  if @was_a_new_record
    ...
  end
end

27

Oysa olanlar için başka bir seçenek, do bir var updated_atzaman damgası:

if created_at == updated_at
  # it's a newly created record
end

Kötü bir fikir değil, ama öyle görünüyor ki bu bazı durumlarda geri tepebilir (illa kurşun geçirmez değil).
Ash Blue

Bir geçişin ne zaman çalıştırıldığına bağlı olarak, created_at ve updated_at kayıtları kapalı olabilir. Ayrıca her zaman birisinin kaydı ilk başta kaydettikten hemen sonra güncelleme şansına sahip olursunuz, bu da zamanı senkronize dışı bırakabilir. Kötü bir fikir değil, sadece daha kurşun geçirmez bir uygulama eklenebilir gibi geliyor.
Ash Blue

Ayrıca kayıt ilk oluşturulduktan çok sonra da eşit olabilirler. Bir kayıt aylarca güncellenmezse, yeni oluşturulmuş gibi görünecektir .
bschaeffer

1
@bschaeffer Üzgünüm, sorum " ilk oluşturulduğu zamandan başka herhangi bir zamanda bir geri aramada created_ateşit updated_atolmak mümkün after_savemü?"
colllin

1
@colllin: Bir kayıt oluştururken created_atve updated_atgeri aramada eşit olacaktır after_save. Diğer tüm durumlarda, after_savegeri aramada eşit olmayacaklardır .
bschaeffer

22

after_createYalnızca kayıt yeni bir kayıt ise, kaydedildikten sonra çağrılan bir geri arama vardır . Ayrıca, after_updatebu değiştirilmiş ve kaydedilmiş mevcut bir kayıt ise kullanılmak üzere bir geri arama da vardır . Geri after_savearama, her iki durumda da after_createveya after_updateçağrıldıktan sonra çağrılır.

after_createYeni bir kayıt kaydedildikten sonra bir şeyin olması gerekiyorsa kullanın .

Daha fazla bilgi burada: http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html


1
Hey, cevabın için teşekkürler, bu bana çok yardımcı oldu. Şerefe dostum, +10 :)
Adam McArthur

1
Bu aslında doğru olmayabilir. Yaratılışınızda ilişkilendirmeleriniz varsa, after_create çağrısı ilişkilendirmelerin oluşturulmasından ÖNCE çağrılır, bu nedenle HER ŞEYİN oluşturulduğundan emin olmanız gerekiyorsa, after_save
Niels Kristian

18

Nesne zaten kaydedildiğinden, önceki değişikliklere bakmanız gerekir. Kimlik yalnızca bir oluşturmadan sonra değişmelidir.

# true if this is a new record
@object.previous_changes[:id].any?

Bir örnek değişkeni de vardır @new_record_before_save. Aşağıdakileri yaparak buna erişebilirsiniz:

# true if this is a new record
@object.instance_variable_get(:@new_record_before_save)

Her ikisi de oldukça çirkin, ancak nesnenin yeni oluşturulup oluşturulmadığını bilmenize izin verirler. Umarım yardımcı olur!


Şu anda after_saveRails 4 kullanarak bir geri aramada hata ayıklama yapıyorum ve bunların hiçbiri bu yeni kaydı tanımlamak için çalışmıyor.
MCB

Bunun @object.previous_changes[:id].any?oldukça basit ve zarif olduğunu söyleyebilirim . Kayıt güncellendikten sonra benim için çalışıyor (onu aramıyorum after_save).
thekingoftruth

1
@object.id_previously_changed?biraz daha az çirkin.
aNoble

@MCB in after_saveon Rails 4 changes[:id]yerine bakmak isteyeceğiniz previous_changes[:id]. Ancak bu (tartışmaya bakınız Rails5.1 değişiyor github.com/rails/rails/pull/25337 )
gmcnaughton

1
previous_changes.key?(:id)daha iyi bir anlayış için.
Sebastian Palma

5

5.1+ yol rayları:

user = User.new
user.save!
user.saved_change_to_attribute?(:id) # => true

1

Rails 4 için (4.2.11.1'de kontrol edilmiştir) sonuçları changesve previous_changesyöntemleri {}içeride nesne oluşturmada boş hashlerdir after_save. Bu nedenle, benzer attribute_changed?yöntemler id_changed?beklendiği gibi çalışmaz.

Ancak bu bilgiden yararlanabilirsiniz ve - en az 1 özelliğin changesgüncellemede olması gerektiğini bilerek - changesboş olup olmadığını kontrol edin . Boş olduğunu onayladıktan sonra, nesne oluşturma sırasında olmalısınız:

after_save do
  if changes.empty?
    # code appropriate for object creation goes here ...
  end
end

0

:idNormalde değişmemesi gerektiğini bildiğim halde spesifik olmayı seviyorum , ama

(byebug) id_change.first.nil?
true

Çok garip beklenmedik bir hata bulmak yerine spesifik olmak her zaman daha ucuzdur.

Aynı şekilde truegüvenilmez argümandan bayrak beklersem

def foo?(flag)
  flag == true
end

Bu, garip böcekler üzerinde oturmamak için çok fazla saat kazandırır.

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.