0

私は Member クラスへの 2 つの belongs_to 関連付けを持つクラス Agreement を持っています - プライマリとセカンダリとして参照されます:

class Agreement < ActiveRecord::Base
  belongs_to :primary, class_name: 'Member'
  belongs_to :secondary, class_name: 'Member'
  ...

  def self.by_member(member_attribute_hash)
    # returns any agreements that has a primary OR secondary member that matches any of the values 
    # in the member_attribute_hash
    ...
  end
end

Member クラスは、Agreement クラスとの関連付けを認識していません。次のことは必要ありません。

class Member < ActiveRecord::Base
  # contains surname, given_names, member_number
  ...

  def self.by_any(member_attribute_hash)
    # returns any member where the member matches on surname OR given_names OR member_number
    ...
  end
end

私がやりたいことは、一次メンバーまたは二次メンバーが一連の基準に一致するすべての契約書を検索することです。

以前の作業 (質問 #14139609 を参照) から、 の条件付き where 句を作成する方法を整理しましたMember.by_any()

契約の検索中にそのメソッドを再利用しようとすると、これを試すようになりました。

class Agreement < ActiveRecord::Base
  ...

  def self.by_member(member_attribute_hash)
    Agreement.joins{primary.outer}.merge(Member.by_any(member_attribute_hash)).joins{secondary.outer}.merge(Member.by_any(member_attribute_hash))
  end
end

を使用してコンソールでこれを実行するmember_attribute_hash = {surname: 'Freud'}と、生成された SQL は、メンバーへの 2 番目の結合用に生成されたエイリアスを受け入れません。

SELECT "agreements".* 
FROM "agreements" 
  LEFT OUTER JOIN "members" 
        ON "members"."id" = "agreements"."primary_id" 
  LEFT OUTER JOIN "members" "secondarys_agreements" 
        ON "secondarys_agreements"."id" = "agreements"."secondary_id" 
WHERE "members"."surname" ILIKE 'Freud%' 
  AND "members"."surname" ILIKE 'Freud%'

WHERE 句の条件が重複していることに注意してください。これにより、プライマリ メンバーの姓が「Freud」のような契約が返されますが、エイリアスがマージを通過しないため、セカンダリ メンバーの条件は無視されます。

何か案は?

4

1 に答える 1

0

これを理解するのに苦労した後、Member.by_anyスコープを Squeelに置き換えましたsifter

class Member < ActiveRecord::Base
  # contains surname, given_names, member_number
  ...

  def self.by_any(member_attribute_hash)
    # returns any member where the member matches on surname OR given_names OR member_number
    squeel do
      [
        (surname =~ "#{member[:surname]}%" if member[:surname].present?),
        (given_names =~ "#{member[:given_names]}%" if member[:given_names].present?),
        (member_number == member[:member_number] if member[:member_number].present?)
      ].compact.reduce(:|)
      # compact to remove the nils, reduce to combine the cases with |
    end
  end
end

と の唯一の (コード的な) 違いは、スコープ内の をsiftersifterscope置き換えたことです。wheresqueel

そのため、 a を使用して Agreement モデルからスコープmergeにアクセスする代わりに、 Agreement モデルから sifter を参照できるようになりました。それは次のように見えました:Member.by_anyMember :by_any

class Agreement < ActiveRecord::Base
  ...

  def self.by_member(member_attribute_hash)
    Agreement.joins{primary.outer}.where{primary.sift :by_any, member_attribute_hash}.joins{secondary.outer}.where{secondary.sift :by_any, member_attribute_hash}
  end
end

これでエイリアシングの問題が修正されました -祝いましょう! :

SELECT "agreements".* 
FROM "agreements" 
  LEFT OUTER JOIN "members" 
        ON "members"."id" = "agreements"."primary_id" 
  LEFT OUTER JOIN "members" "secondarys_agreements" 
        ON "secondarys_agreements"."id" = "agreements"."secondary_id" 
WHERE "members"."surname" ILIKE 'Freud%' 
  AND "secondarys_agreements"."surname" ILIKE 'Freud%'

しかし、私はまだ期待した結果を得ていませんでした -お祝いは保留されました. 何が問題だったのですか?ANDwhere 節の が間違っていました。もう少し掘り下げた後(そしてコンピューターから一晩離れた後)、リフレッシュした心はこれを試すことにしました:

class Agreement < ActiveRecord::Base
  ...

  def self.by_member(member_attribute_hash)
    Agreement.joins{primary.outer}.joins{secondary.outer}.where{(primary.sift :by_any, member_attribute_hash) | (secondary.sift :by_any, member_attribute_hash)}
  end
end

これを生成する:

SELECT "agreements".* 
FROM "agreements" 
  LEFT OUTER JOIN "members" 
        ON "members"."id" = "agreements"."primary_id" 
  LEFT OUTER JOIN "members" "secondarys_agreements" 
        ON "secondarys_agreements"."id" = "agreements"."secondary_id" 
WHERE ((("members"."surname" ILIKE 'Freud%') 
   OR ("secondarys_agreements"."surname" ILIKE 'Freud%')))

ああ、素敵な...再開のお祝い...今、単一のシフターで定義されたルールに従って一致するプライマリまたはセカンダリメンバーを持つ契約を取得します。

そして、彼が Squeel で行ったすべての作業に対して、Ernie Miller に大声で叫びます。

于 2013-03-07T15:53:50.600 に答える