2017-02-09 5 views
2

「OR」クエリを2つのスコープに組み合わせたクエリを作成したいとします(Rails 4を使用していますが、ActiveRecordまたは1つのスコープが1つのスコープに結合されている2つのスコープを持つクエリ

MODEL1

scope :association_has_email, -> { joins(:model2).where.not(model2s:{email:nil}) } 
scope :description_has_email, -> { where("description ~* ?", email_regex) } 

(email_regexが電子メールを選び出す正規表現です)。

SELECT \"model1s\".* FROM \"model1s\" WHERE (description ~* '[[:<:]][A-Z0-9._%+-][email protected][A-Z0-9.-]+.[A-Z]{2,4}[[:>:]]') 
SELECT \"model1s\".* FROM \"model1s\" INNER JOIN \"model2s\" ON \"model2s\".\"id\" = \"model1s\".\"model2_id\" WHERE (\"model2s\".\"email\" IS NOT NULL) 

を電子メールは、テキストでの会合または埋め込まれた電子メールの中にあるいずれかのこれらの機会を選び出すためのスコープを作成します。私たちはようなSQL与え

片方が結合を必要とし、もう一方が結合しない "OR"クエリをどのように記述しますか?

+0

参照してください。http://stackoverflow.com/questions/31096009/activerecord-or-query-hash-notation –

+1

where-or gem(華麗です...)では、 "ArgumentError:Relationが#またはに渡されます構造的に互換性がなければなりません " しかし、スコープにジョインを渡すと、email_in_descriptionにmodel2がまったくない場合は除外されます。 しかし、私には解決策があると思います。外部結合を取得するためにインクルードすることができます... – Carpela

+0

ActiveRecord DSLが素晴らしいツールではないところで、生のSQLを使用することを常に提案します。 – MurifoX

答えて

0

[OK]をクリックします。あなたは

ArgumentError: Relation passed to #or must be structurally compatible 

で終わる上のRails 4の場合 は、どこが-や宝石レール5のように生成したり、クエリの修正を提供し、あなたはスコープを渡すただし場合は、次を使用することができます。

scope :email_somewhere, -> { association_has_email.or(Model1.joins(:model2).description_has_email } 

SELECT \"model1s\".* FROM \"model1s\" INNER JOIN \"model2s\" ON \"model2s\".\"id\" = \"model1s\".\"model2_id\" WHERE ((\"model2s\".\"email\" IS NOT NULL) OR (description ~* '[[:<:]][A-Z0-9._%+-][email protected][A-Z0-9.-]+.[A-Z]{2,4}[[:>:]]')) 

動作しますが、内部結合を使用するため、説明に電子メールが含まれていてmodel2は含まれないものは除外されます。

ただし、includeを使用すると、目的の結果が得られます。

scope :association_has_email, -> { includes(:model2).where.not(model2s:{email:nil}) } 
scope :description_has_email, -> { where("description ~* ?", email_regex) } 

あなたは違いがSQLはMODEL1から属性のすべてを引き出し、その後、左の外側にはMODEL2クエリのために参加する追加され

scope :email_somewhere, -> { association_has_email.or(Model1.includes(:model2).description_has_email } 

を使用できることを意味します。

SELECT [...all the model1 attributes...] LEFT OUTER JOIN \"model2s\" ON \"model2s\".\"id\" = \"model1s\".\"model2_id\" WHERE ((\"model2s\".\"email\" IS NOT NULL) OR (description ~* '[[:<:]][A-Z0-9._%+-][email protected][A-Z0-9.-]+.[A-Z]{2,4}[[:>:]]')) 

最初のインナージョイントを使用する必要があったのですが、私にとっては効果的です。

0

次のような1つの以上のスコープを作成することができます。

scope :check_email, -> { 
    if email is embedded 
    association_has_email 
    else 
    description_has_email 
    end 
} 
+0

ここに「埋め込み」とは何ですか? – Carpela

+0

これはちょうどあなたが検索したい電子メールがどこにあるか確認することです –

+0

混乱しているビット。私たちがしようとしているのは、私たちの記録の1つに「何らかの」電子メールがあるかどうかを調べることです。私たちは、直接コミュニケーションをとる手段があるかどうかを考えています。すなわち、スコープがフィルタリングしようとしているメールがあるかどうかは、事前にわかりません) – Carpela

関連する問題