多使用多belongs_to的关联

问题描述:

我有两个belongs_to的协会会员类的类协议连接到相同型号 - 引用为原发性和继发性:多使用多belongs_to的关联

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 

会员类没有关联的知识该协议类 - 它并不需要:

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 

我想要做的就是搜索,其中主要或次要构件的一套标准匹配的所有协议。

从以前的工作(see question #14139609),我已经整理了如何为Member.by_any()构建条件where子句。

试图重新使用方法,同时寻求协议使我试试这个:

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不履行的第二个连接产生的别名到会员:

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子句中的重复条件。这将返回主要成员姓氏如“弗洛伊德”的协议,但会忽略次要成员条件,因为别名不通过合并。

任何想法?

努力理解这一点之后,我结束了一个Squeel sifter更换Member.by_any范围:

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 

唯一的区别(代码明智),bewteen的sifterscope被更换where的在筛选器中的范围为squeel

所以,而是采用了merge访问从协议模型Member.by_any范围,现在我可以从协议参考模型的Member :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%' 

但我还是没有得到我希望的结果 - 庆祝搁置。什么问题? Where子句中的AND错误。多一点挖(一夜远离电脑)后,刷新头脑决定试试这个:

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%'))) 

甜啊... 重启庆典。 ..现在我得到的协议有一个主要或次要成员,根据单个筛选器中定义的规则进行匹配。

对于他在斯奎尔所做的所有工作,一个大喊大叫的是厄尼米勒。