次の2つのオブジェクトがあるとします。
first_name_relation = User.where(:first_name => 'Tobias') # ActiveRecord::Relation
last_name_relation = User.where(:last_name => 'Fünke') # ActiveRecord::Relation
2つの関係を組み合わせて、両方の条件を含む1つのActiveRecord::Relation
オブジェクトを生成することは可能ですか?
注:この動作を取得する場所をチェーン化できることを知っています。本当に興味があるのは、2つの別個のActiveRecord::Relation
オブジェクトがある場合です。
関係オブジェクトは配列に変換できます。これにより、後でそれらに対してActiveRecordメソッドを使用できなくなりますが、必要はありませんでした。これは私がしました:
name_relation = first_name_relation + last_name_relation
Ruby 1.9、Rails 3.2
merge
は、実際にはOR
のようには機能しません。単なる交差点(AND
)
ActiveRecord :: Relationオブジェクトを1つにまとめるためにこの問題に苦労しましたが、実用的な解決策が見つかりませんでした。
これら2つのセットからユニオンを作成する正しい方法を探す代わりに、セットの代数に焦点を当てました。 De Morganの法則 を使用して別の方法でそれを行うことができます
ActiveRecordはマージメソッド(AND)を提供します。また、not methodまたはnone_of(NOT)を使用できます。
search.where.none_of(search.where.not(id: ids_to_exclude).merge(search.where.not("title ILIKE ?", "%#{query}%")))
あなたはここにいます(A u B) '= A' ^ B '
更新:上記のソリューションは、より複雑なケースに適しています。あなたの場合、そのようなsmthは十分でしょう:
User.where('first_name LIKE ? OR last_name LIKE ?', 'Tobias', 'Fünke')
Railsの組み込みArelを使用することで、多くの奇妙な状況でもこれを達成することができました。
User.where(
User.arel_table[:first_name].eq('Tobias').or(
User.arel_table[:last_name].eq('Fünke')
)
)
これは、Arelのorを使用して、両方のActiveRecord関係をマージします。
ここで提案されたように、Mergeは私にとってはうまくいきませんでした。結果から関係オブジェクトの2番目のセットを削除しました。
active_record_union というgemがあります。これはあなたが探しているものかもしれません。
使用例は次のとおりです。
current_user.posts.union(Post.published)
current_user.posts.union(Post.published).where(id: [6, 7])
current_user.posts.union("published_at < ?", Time.now)
user_1.posts.union(user_2.posts).union(Post.published)
user_1.posts.union_all(user_2.posts)
これは、pluckを使用して各レコードの識別子を取得し、配列を結合し、最後に結合されたIDのクエリを実行する場合の「処理」方法です。
transaction_ids = @club.type_a_trans.pluck(:id) + @club.type_b_transactions.pluck(:id) + @club.type_c_transactions.pluck(:id)
@transactions = Transaction.where(id: transaction_ids).limit(100)
Activerecord関係の配列があり、それらすべてをマージしたい場合は、次のことができます。
array.inject(:merge)
ブルートフォースそれ:
first_name_relation = User.where(:first_name => 'Tobias') # ActiveRecord::Relation
last_name_relation = User.where(:last_name => 'Fünke') # ActiveRecord::Relation
all_name_relations = User.none
first_name_relation.each do |ar|
all_name_relations.new(ar)
end
last_name_relation.each do |ar|
all_name_relations.new(ar)
end
私はこの問題に何回かつまずきましたが、一般に受け入れられている応答は私にとってはうまくいきませんでした。
受け入れられた答えの提案された解決策は、最もうまくいくように見えました:
first_name_relation.or(last_name_relation)
しかし、これを機能させることは決してできず、「または」に対して「未定義のメソッド」エラーを常に受け取ります。
私の解決策:
combined_relation = first_name_relation + (last_name_relation - first_name_relation)
これにより、元のクエリとリレーションオブジェクトとの間のUNIONの結果が基本的に正しいActiveRecordオブジェクトのままになります。
これは@thatmiddlewayが提供する答えに似ていますが、オブジェクトのDISTINCTコレクションを取得するには減算を追加する必要がありました。これにより、結合されたコレクションがARRAYに変換されますが、ビュー内の「各」イテレーターの個々のインスタンスでモデルメソッドを呼び出すことができ、問題を解決しました。
これが私の最初のStackOverflowの回答(gasp!)なので、フィードバックをお待ちしています!