Ruby on rails 是否可以在Rails中创建或连接以获取与两个不同模型相交的记录?
我还发布了一个相关的问题:,更多的是关于这个概念 我试图做的是:我想找到某个Ruby on rails 是否可以在Rails中创建或连接以获取与两个不同模型相交的记录?,ruby-on-rails,Ruby On Rails,我还发布了一个相关的问题:,更多的是关于这个概念 我试图做的是:我想找到某个用户为其创建了报告的帐户,或用户有截止日期的 scope :active_accounts_for_user, -> (user) { joins(:deadlines) .where(:deadlines => {user: [nil, user]}) .joins(:reports) .where(:reports => {user: user, day: (Da
用户为其创建了报告的帐户,或用户有截止日期的
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,我在一个简单的示例中使用它,其中:
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)
}
这是对作用域的正确使用吗?在Rails 5.0及更高版本中是可能的
指南中有一节介绍了如何做到这一点:
连接的唯一缺点是它们需要在两个关系中复制,以使整个查询在结构上兼容:
scope :active_accounts_for_user, -> (user) {
joins(:deadlines).joins(:reports).where(deadlines: ...).or(
joins(:deadlines).joins(:reports).where(reports: ...)
)
}
一种选择是使用普通SQL
如果我正确理解了您的模式,那么您所追求的是需要左连接而不是OR运算符的东西。内部联接上的OR运算符将无法实现您希望的结果,因为任何只有截止日期但没有报告的记录都不会被返回。相反,LEFT JOIN会返回在截止日期或报表表中有匹配用户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子句的第二个where子句,有效地避免了纯文本条件,以确保报告和截止日期都不是空的
如果通过“用户”属性将表连接在一起,则可以使用普通活动记录查询来使用
Account.includes(:accounts).includes(:deadlines).where...
见:
另一种避免左联接的方法是在一个表上使用内部联接,在另一个表上使用具有内部联接的类似查询进行联合。为此,您必须使用指定返回的字段。选择以确保联合可以工作。在我看来,这更棘手
不管是哪种方式,编写包含用户条目的where子句条件的SQL通常都比较容易,而不是猜测Rails将如何创建所需的查询。即使您提到的链接可能会解决这个问题,但是在这里包含代码的相关部分也更合适。否则,它很可能只是对这个问题的一个评论。不幸的是,这只适用于Rails 5。是否有与Rails 4相当的版本?它是在Rails 5.0中添加的,以前的版本不支持或查询。需要使用纯SQL编写。您可以尝试为Rails 3和Rails 4实现或方法。不会留下连接给我所有帐户吗?如果设置了截止日期,where子句应该通过限制用户和日期范围来涵盖这一点。也就是说,您需要扩展条件以排除截止日期和报告都为空的结果。我将编辑我的答案,以包括这一可能性。谢谢,伟大的解决方案。