首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >是否可以在Rails中创建或连接以获取与两个不同模型相交的记录?

是否可以在Rails中创建或连接以获取与两个不同模型相交的记录?
EN

Stack Overflow用户
提问于 2018-06-01 06:55:03
回答 2查看 463关注 0票数 1

我还发布了一个相关的问题:https://stackoverflow.com/a/50613524?noredirect=1,它更多地是关于这个概念的。

我要做的是:我想找到某个User为其创建了用户拥有deadlineReportReport

代码语言:javascript
复制
  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:

代码语言:javascript
复制
  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)
  }

这是一个范围的正确使用吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-06-01 07:52:05

一种选择是使用普通SQL。

如果我正确地理解了您的架构,那么您需要的东西比OR操作符更需要左联接。内部联接上的OR操作符不会达到您的期望,因为任何只有截止日期但没有报告的记录都不会被返回。相反,左联接返回在截止日期或报表表中有匹配的user_id的所有帐户记录。

代码语言:javascript
复制
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子句。因此,这将成为:

代码语言:javascript
复制
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属性连接表的关联,则可以使用普通的活动记录查询来使用。

代码语言:javascript
复制
Account.includes(:accounts).includes(:deadlines).where... 

请参阅:querying.html#specifying-conditions-on-eager-loaded-associations

避免左联接的另一种选择是在一个表上使用内部连接,在另一个表上使用与内部连接类似的查询的UNION。为此,您必须使用.select指定返回的字段,以确保联合能够工作。在我看来,这更棘手。

但是,无论哪种方式,编写SQL到包含用户条目的where子句条件点通常都比较容易,而不是试图猜测Rails将做什么来创建您想要的查询。

票数 1
EN

Stack Overflow用户

发布于 2018-06-01 07:03:49

这在Rails 5.0和更高版本中是可能的。

在指南中有一节介绍了如何做到这一点:querying.html#or-conditions

联接的唯一问题是,它们需要复制两个关系,才能使整个查询在结构上兼容:

代码语言:javascript
复制
scope :active_accounts_for_user, -> (user) {
 joins(:deadlines).joins(:reports).where(deadlines: ...).or(
   joins(:deadlines).joins(:reports).where(reports: ...)
  )
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50637703

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档