Array Rails ActiveRecord içindeki kimliğin istisnasız olarak nasıl seçileceği


135

Kimlikleri bir dizi var, gibi

ids = [2,3,5]

ve ben yaparım

Comment.find(ids)

her şey iyi çalışıyor. Ama olmayan bir kimlik olduğunda, bir istisna alıyorum. Bu, bazı filtrelerle eşleşen kimliklerin listesini aldığımda ve böyle bir şey yaptığımda ortaya çıkar

current_user.comments.find(ids)

Bu sefer geçerli bir yorum kimliğine sahip olabilirim, ancak verilen Kullanıcıya ait değil, bu yüzden bulunamadı ve bir istisna alıyorum.

Denedim find(:all, ids), ama tüm kayıtları döndürüyor.

Şimdi yapabilmemin tek yolu

current_user.comments.select { |c| ids.include?(c.id) }

Ama bu bana süper verimsiz bir çözüm gibi geliyor.

Mevcut olmayan kayıtta istisna olmadan Array'da kimlik seçmenin daha iyi bir yolu var mı ?

Yanıtlar:


216

Eğer sadece endişe duyduğunuz istisnayı önlüyorsa, "find_all_by .." fonksiyon ailesi istisnalar atmadan çalışır.

Comment.find_all_by_id([2, 3, 5])

bazı kimlikler olmasa bile çalışır. Bu çalışır

user.comments.find_all_by_id(potentially_nonexistent_ids)

durumda.

Güncelleme: Raylar 4

Comment.where(id: [2, 3, 5])

bu benim tercih ettiğim çözüm, istisna yönetim rotasından daha temiz görünüyor
Sam Saffron

5
: (Koşullara => [ "? Onaylanmış ve kimliği içinde ()", [1,2,3]]) Bu başka uzantısı olarak, zincir karmaşık koşullara gerektiğinde, hatta Comment.all yapabileceğini
Ömer Kureyşi

14
bu Rails 4'te kullanımdan kaldırılacak: edgeguides.rubyonrails.org/…
Jonathan Lin

3
@JonathanLin doğru, mjnissim'in cevabı tercih edilmelidir: stackoverflow.com/a/11457025/33226
Gavin Miller

6
Bu , daha sonra onunla ne yapabileceğinizi sınırlayan bir Arrayyerine döndürür ActiveRecord::Relation. Comment.where(id: [2, 3, 5])geri döner ActiveRecord::Relation.
Joshua Pinter

148

Güncelleme: Bu cevap Rails 4.x için daha alakalı

Bunu yap:

current_user.comments.where(:id=>[123,"456","Michael Jackson"])

Bu yaklaşımın daha güçlü tarafı, Relationdaha fazla .wherecümle, .limitcümle vb. Katılabileceğiniz bir nesneyi döndürmesidir ki bu çok yararlıdır. İstisnalar olmadan varolmayan kimliklere de izin verir.

Daha yeni Ruby sözdizimi şöyle olur:

current_user.comments.where(id: [123, "456", "Michael Jackson"])

whereBir diziyle karşılaştırırken sözdizimini onayladığınız için teşekkür ederiz . Ben bir INifade ile SQL kodlamak zorunda olabileceğini düşündüm , ama bu daha temiz görünüyor ve kullanımdan kaldırılmış için kolay bir yedek scoped_by_id.
Mark Berry

1
Buna ne denir ve nasıl çalışır? Rails büyü mü ?! Bir meslektaşın yorumladığı gibi, 'bir tamsayıyı bir nesne listesiyle karşılaştırmak' gibi.
atw

23

Daha fazla kontrole ihtiyacınız varsa (belki de tablo adını belirtmeniz gerekir) aşağıdakileri de yapabilirsiniz:

Model.joins(:another_model_table_name)
  .where('another_model_table_name.id IN (?)', your_id_array)

Tam aradığım şey. Teşekkürler!
Myxtic

your_id_arrayNesneleri ne zaman geri aldığınızın sırasını korumanın bir yolu var mı ?
Joshua Pinter

@JoshPinter Veritabanının aynı sırayla geri dönmesini beklemenin güvenilir bir yol olduğunu düşünmüyorum. Belki de doğru şeyleri sağlamak için sonunda bir ORDER BY sorgusu ekleyin.
Jonathan Lin

@JonathanLin Yanıtınız için teşekkürler Jonathan. Kesinlikle haklısın. Durumumda bir ORDER BYözniteliğe dayalı olmadığından, bir durumun kullanılması işe yaramaz. Ancak, SQL yoluyla yapmanın bir yolu var (bu yüzden hızlı) ve birisi bunun için bir mücevher bile yarattı. Bu soru ve
Joshua Pinter

10

Şimdi .find ve .find_by_id yöntemleri raylar 4'te kullanımdan kaldırılmıştır. Bunun yerine aşağıda kullanabiliriz:

Comment.where(id: [2, 3, 5])

Bazı kimlikler olmasa bile çalışır. Bu çalışır

user.comments.where(id: avoided_ids_array)

Kimlikleri hariç tutmak için de

Comment.where.not(id: [2, 3, 5])

3
github.com/rails/activerecord-deprecated_finders .find ve .find_by_id yöntemleri ray 4'te kullanımdan kaldırılmaz.
Canna

0

İstisnaların uygulamanızı öldürmesini önlemek için, bu istisnaları yakalamanız ve onlara istediğiniz gibi davranmanız ve kimliğinizin bulunmadığı durumlarda uygulamanız için davranışı tanımlamanız gerekir.

begin
  current_user.comments.find(ids)
rescue
  #do something in case of exception found
end

İşte fazla bilgi yakut istisnalar üzerinde.


1
evet bu sorunu çözdü, ama gerçekten temiz bir çözüm değil
Jakub Arnold

3
Bir istisna yakalayacaksanız, yakalamayı beklediğiniz istisnayı bildirmeniz gerekir, aksi takdirde beklemediğiniz ve gerçek bir sorunu gizlemediğiniz bir şeyi yakalama riskiyle karşı karşıya kalırsınız.
Haegin

0

Eğer başka şartlar koymak istiyorsanız, adlandırılmış_skop içinde de kullanabilirsiniz

örneğin başka bir model ekleyin:

isimli_scope 'get_by_ids', lambda {| ids | {: include => [: yorumlar],: koşullar => ["comments.id IN (?)", ids]}}

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.