2

在 Rails3 中,我有:

Class Teacher
  #  active                 :boolean
  has_and_belongs_to_many :subjects

Class Subject
  #  active                 :boolean
  has_and_belongs_to_many :teachers

我正在尝试构建一个 Teacher 范围,该范围返回所有Teachersactivea 相关的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})
4

4 回答 4

5

你得救Squeel你。更多细节在这里

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

class Teacher
  ...
  scope :active_teachers, joins{subjects}.where {(active == true) | (subjects.active == true)}
  ...
end
于 2013-05-12T11:14:54.367 回答
3

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

AREL OR 条件

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

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

祝你好运!

于 2013-05-15T15:43:41.737 回答
3

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

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

像这样的东西应该工作:

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

不太优雅,但可以包装成一个方法以供重用。

于 2013-05-12T11:36:14.683 回答
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
于 2013-05-15T16:58:07.807 回答