我有一个类协议,它与成员类有两个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子句中的重复条件。这将返回协议,其中主要成员具有类似“弗洛伊德”的姓氏,但忽略了辅助成员条件,因为别名没有流经合并。
有什么想法吗?
答案 0 :(得分: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
sifter
和scope
之间的唯一区别(代码方式)是替换范围中的where
并使用squeel
。{ / p>
因此,我现在无法使用merge
来访问协议模型中的Member.by_any
范围,而是可以从协议模型中引用Member :by_any
sifter。看起来像是:
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%')))
很可爱...... 重新开始庆祝活动 ...现在我得到的协议中有一个主要或次要成员,根据单个筛子中定义的规则进行匹配。
对于他在Squeel所做的所有工作,Ernie Miller大肆宣传。