我还发布了一个相关的问题:https://stackoverflow.com/a/50613524?noredirect=1,它更多地是关于这个概念的。
我要做的是:我想找到某个User为其创建了用户拥有deadline的Report、或的Report、或。
scope :active_accounts_for_user, -> (user) {
joins(:deadlines)
.where(:deadlines => {user: [nil, user]})
.joins(:reports)
.where(:reports => {user: user, day: (Date.today - 1.day..Date.today)})
}这方面的问题是Rails创建了一个AND查询,因此它只会找到同时有报告和截止日期的帐户。这显然限制了我的使用。
编辑:好的,我找到了一个解决方案,我想确认这是否是一个好的实践。我基本上是在为这两个模型创建单独的查询,以便获取帐户ID,我在一个简单的地方使用了这个ID:
scope :active_accounts_for_user, -> (user) {
accounts_with_reports = Report.where(user: user).where('date > ?', 24.hours.ago).pluck(:account_id)
accounts_with_deadlines = Deadline.where(user: user).pluck(:account_id)
account_ids = (accounts_with_reports + accounts_with_deadlines).compact
return includes(:past_deadlines, :deadlines).where(id: account_ids)
}这是一个范围的正确使用吗?
发布于 2018-06-01 07:52:05
一种选择是使用普通SQL。
如果我正确地理解了您的架构,那么您需要的东西比OR操作符更需要左联接。内部联接上的OR操作符不会达到您的期望,因为任何只有截止日期但没有报告的记录都不会被返回。相反,左联接返回在截止日期或报表表中有匹配的user_id的所有帐户记录。
select * from accounts
left join deadlines on deadlines.user = accounts.user
left join reports on reports.user = accounts.user
where day ...
and (reports.user IS NOT NULL or deadline.user IS NOT NULL)在Rails 4中,我相信您可以指定联接的SQL代码,同时像通常那样链接where子句。因此,这将成为:
joinsql = "left join deadlines on
deadlines.user = accounts.user
left join reports
on reports.user = accounts.user"
Account.join(joinsql).where(
accounts: {user: user},
deadline: {day: (Date.today - 1.day..Date.today)}
).where("reports.user IS NOT NULL or deadlines.user IS NOT NULL")然后,可以访问所有已连接表的结果。
注意添加了第二个where子句,有效地将其链接到第一个,并对纯文本条件进行了修改,以确保报告和截止日期都不是空的。
如果存在通过user属性连接表的关联,则可以使用普通的活动记录查询来使用。
Account.includes(:accounts).includes(:deadlines).where... 请参阅:querying.html#specifying-conditions-on-eager-loaded-associations
避免左联接的另一种选择是在一个表上使用内部连接,在另一个表上使用与内部连接类似的查询的UNION。为此,您必须使用.select指定返回的字段,以确保联合能够工作。在我看来,这更棘手。
但是,无论哪种方式,编写SQL到包含用户条目的where子句条件点通常都比较容易,而不是试图猜测Rails将做什么来创建您想要的查询。
发布于 2018-06-01 07:03:49
这在Rails 5.0和更高版本中是可能的。
在指南中有一节介绍了如何做到这一点:querying.html#or-conditions
联接的唯一问题是,它们需要复制两个关系,才能使整个查询在结构上兼容:
scope :active_accounts_for_user, -> (user) {
joins(:deadlines).joins(:reports).where(deadlines: ...).or(
joins(:deadlines).joins(:reports).where(reports: ...)
)
}https://stackoverflow.com/questions/50637703
复制相似问题