【问题标题】:Using OR with queries in a scope对范围内的查询使用 OR
【发布时间】:2023-04-08 01:58:01
【问题描述】:

在 Rails3 中我有:

Class Teacher
  #  active                 :boolean
  has_and_belongs_to_many :subjects

Class Subject
  #  active                 :boolean
  has_and_belongs_to_many :teachers

我正在尝试构建一个 Teacher 范围,它返回所有 activeTeachers 或与 Subject 相关联的 active

这些作用域单独工作,但是如何将它们作为一个单个作用域与 OR 结合起来?

scope :active_teachers, where(active: true)
scope :more_active_teachers, joins(:subjects).where(:subjects => {active: true})

我试过这个没有成功:

scope :active_teachers, where(active: true).or(joins(:subjects)
      .where(:subjects => {active: true}))

更新:

我以为我有一个解决方案,但这不再是延迟加载,而是两次访问数据库并且——最重要的是——返回一个数组而不是一个 AR 对象!

scope :active_teachers, where(active: true) |
                        joins(:subjects).where(:subjects => {active: true})

【问题讨论】:

  • 查看我对同一问题的回答here。还要注意类似的问题herehere

标签: ruby-on-rails ruby-on-rails-3 activerecord


【解决方案1】:

对此有一个 Rails 拉取请求 (https://github.com/rails/rails/pull/9052),但与此同时,有人创建了一个猴子补丁,您可以将其包含在您的初始化程序中,这将允许您执行此操作并仍然给您一个 ActiveRecord::Relation

https://gist.github.com/j-mcnally/250eaaceef234dd8971b

这样,您就可以像这样对您的范围进行 OR 操作

Teacher.active_teachers.or.more_active_teachers

或者写一个新的作用域

scope :combined_scopes, active_teachers.or.more_active_teachers

【讨论】:

  • 谢谢 keithepley,我会留意那个。我有点不愿意离开规范路径,但那个补丁可以解决问题。谢谢。
【解决方案2】:

您可以通过访问 AREL 来解决此问题。请参阅此 SO Question 以了解如何执行此操作。

AREL OR Condition

或来自AREL Source Code README.md。我认为(但尚未验证)对于您的特定示例,这将转化为以下内容。

teachers.where(teachers[:active].eq(true).or(subjects[:active].eq(true)))

祝你好运!

【讨论】:

  • 谢谢戴夫!我需要进一步探索。
【解决方案3】:

我认为简短的回答是你不能。

在代码中进行 Oring 会破坏延迟加载……因为您需要数据库来进行评估,所以真的没有办法解决它。如果不单独执行每个子条款,ActiveRecord 就无法对范围进行评估。

这样的事情应该可以工作:

joins(:subjects).where("subjects.active = true OR teachers.active = true")

没有那么优雅,但可以封装成一个方法以供重用。

【讨论】:

  • 你还需要加入:scope :active_teachers, joins(:subjects).where("subjects.active = true OR teachers.active = true")
  • 即使这不那么优雅,它也更简单。在某些时候,不值得为了两个条件一起跳槽。
  • 这就是我的感觉
  • 谢谢托比 - 我同意你的观点。不幸的是,我无法获得上述查询来给出我所追求的结果(即,似乎重复计算了具有活跃科目的教师,并且没有返回自己活跃的教师)。我宁愿避免使用另一个宝石,但我认为我需要选择 Squeel。感谢您的帮助!
【解决方案4】:

Squeel 可以帮助您。更多详情here.

使用它,您可以定义如下内容:

class Teacher
  ...
  scope :active_teachers, joins{subjects}.where {(active == true) | (subjects.active == true)}
  ...
end

【讨论】:

  • +1 表示 Squeel。它是复杂应用的绝佳资源。
  • +1。谢谢普内特。我希望避免使用另一个 gem,但 Squeel 似乎是理想的解决方案,无论如何我在项目的后期肯定会需要它。你得到了大勾号。谢谢。
猜你喜欢
  • 1970-01-01
  • 2014-05-30
  • 2020-10-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-23
  • 2011-04-10
  • 1970-01-01
  • 2022-01-12
相关资源
最近更新 更多