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子句应该通过限制用户和日期范围来涵盖这一点。也就是说,您需要扩展条件以排除截止日期和报告都为空的结果。我将编辑我的答案,以包括这一可能性。谢谢,伟大的解决方案。