Array Rails ActiveRecordのIDを例外なく選択する方法


135

次のようなIDの配列がある場合

ids = [2,3,5]

そして私は演奏します

Comment.find(ids)

すべてが正常に動作します。しかし、存在しないIDがあると、例外が発生します。これは一般的に、いくつかのフィルターに一致するIDのリストを取得し、次のような場合に発生します

current_user.comments.find(ids)

今回は有効なコメントIDを持っている可能性がありますが、これは特定のユーザーに属していないため、見つかりませんでした。例外が発生します。

私は試しましたがfind(:all, ids)、すべてのレコードが返されます。

今私ができる唯一の方法は

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

しかし、それは私にとって非常に非効率的なソリューションのようです。

存在しないレコードで例外を発生させずに配列でIDを選択するより良い方法はありますか?

回答:


216

心配している例外を回避するだけの場合は、「find_all_by ..」関数ファミリーが例外をスローせずに機能します。

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

一部のIDが存在しない場合でも機能します。これは

user.comments.find_all_by_id(potentially_nonexistent_ids)

ケースも。

アップデート:Rails 4

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

これは私の推奨ソリューションです。例外処理ルートよりもきれいに見えます
Sam Saffron

5
これの別の拡張として、複雑な条件を連鎖する必要がある場合は、Comment.all(:conditions => ["approved and id in(?)"、[1,2,3]])
Omar Qureshi

14
これはRails 4で廃止される予定です:edgeguides.rubyonrails.org/…–
Jonathan Lin

3
@JonathanLinがmjnissimの答えが好まれるべき、正しいです:stackoverflow.com/a/11457025/33226
ギャビン・ミラー

6
これはのArray代わりにを返します。これにより、ActiveRecord::Relation後で何ができるかが制限されます。Comment.where(id: [2, 3, 5])を返しますActiveRecord::Relation
Joshua Pinter 14年

148

更新:この回答はRails 4.xにより関連しています

これを行う:

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

このアプローチのより強い側面は、Relationより多くの.where句、.limit句などを結合できるオブジェクトを返すことです。これは非常に役立ちます。また、例外をスローすることなく、存在しないIDを許可します。

新しいRuby構文は次のようになります。

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

where配列と比較するときに構文を確認していただきありがとうございます。SQLをINステートメントでコーディングする必要があるかもしれないと思いましたが、これは見た目がすっきりしていて、非推奨のの簡単な置き換えですscoped_by_id
Mark Berry

1
これは何と呼ばれ、どのように機能しますか?Railsの魔法ですか?同僚がコメントしたように、それは「オブジェクトリストと整数の比較」のようなものです
atw

23

さらに制御が必要な場合(おそらく、テーブル名を指定する必要がある場合)は、次の操作も実行できます。

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

まさに私が探していたもの。ありがとう!
Myxtic 2015

your_id_arrayオブジェクトを取り戻すときにの順序を維持する方法はありますか?
Joshua Pinter

@JoshPinterこれは、データベースが同じ順序で物事を返すことを期待する信頼できる方法だとは思いません。おそらく最後にORDER BYクエリを追加して、物事の正しい順序を確認します。
ジョナサン・リン

@JonathanLin回答Jonathanをありがとう。あなたは確かに正しい。使用するORDER BYためには、属性に基づいていないので、私の状況では動作しません。ただし、SQLを介してそれを行う方法があり(そのため高速です)、誰かがそのためのgemを作成しました。このQ&Aをチェックアウト:stackoverflow.com/questions/801824/...
ジョシュア・ピンター

10

.findメソッドと.find_by_idメソッドはrails 4では非推奨になりました。そのため、代わりに以下を使用できます。

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

一部のIDが存在しない場合でも機能します。これは

user.comments.where(id: avoided_ids_array)

IDを除外するためにも

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

3
github.com/rails/activerecord-deprecated_findersは .findと.find_by_id方法は、レール4には非推奨されません
カンナ

0

例外によるアプリの強制終了を回避するには、それらの例外をキャッチして希望どおりに処理し、IDが見つからない状況でのアプリの動作を定義する必要があります。

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

ルビーの例外についての詳細はこちらです。


1
うん、これは問題を解決しますが、それは本当にきれいな解決策ではないのです
ヤクブ・アーノルド

3
例外をキャッチする場合は、キャッチするはずの例外を宣言する必要があります。宣言しないと、予期しないものをキャッチして実際の問題を隠すリスクがあります。
ヘギン2014年

0

他の条件をそこに置きたい場合は、named_scopeでも使用できます。

たとえば、他のいくつかのモデルを含めます。

named_scope 'get_by_ids'、lambda {| ids | {:include => [:comments]、:conditions => ["comments.id IN(?)"、ids]}}

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.