1

Child1 和 Child2 与 Entity 具有 STI 关系,而 Child2 具有_many Child1。Child1 有一个由 AASM 管理的状态列。

class Entity < ActiveRecord::Base
end

class Child1 < Entity
  include AASM
  aasm_column 'status' do
    state :owned #also creates scope Child1.owned
    state :sold
  end

  belongs_to :child2
end

class Child2 < Entity
  has_many :child1s
end

我想为 Child1 上的每个状态在 Child2 上创建一个范围。它应该返回具有一个或多个处于该状态的 Child1 记录的所有 Child2 记录。理想情况下,它将重用 AASM 自动创建的范围,例如

scope :owned, -> {joins(:child1s).merge(Child1.owned)} #in Child2

...它又好又干净又干。不幸的是,这生成的 SQL 被同一张表上的连接混淆了:

irb(main):001:0> Child2.owned
  Child2 Load (35.5ms)  SELECT "entities".* FROM "entities"
INNER JOIN "entities" "child1_entities" ON "child1_entities"."child2_id" = "entities"."id" AND "child1_entities"."type" IN ('Child1')
WHERE "entities"."type" IN ('Child2') AND "entities"."status" = 'owned'

where 子句的最后一部分应该是child1_entities.status = 'owned'.

我可以用 SQL 或 Arel 编写整个查询,但我希望找到一些东西,即使我必须去那里为 child1 连接指定别名,我仍然可以重用我在 Child1 中已有的范围。

4

1 回答 1

3

您可以在不使用任何具有几个范围关系的第三方 gem 的情况下执行此操作

class Child2 < Entity
  has_many :child1s
  has_many :owned_child1s, -> {owned}, class_name: "Child1"
  has_many :sold_child1s, -> {sold}, class_name: "Child1"
end

然后找到所有拥有或出售的 Child2 :child1s 分别使用以下查询

Child2.joins(:owned_child1s) #=> All Child2 having owned children
Child2.joins(:sold_child1s)  #=> All Child2 having sold children

您可以使用以下方法将其设为 Child2 的范围:

class Child2 < Entity    
  has_many :child1s
  has_many :owned_child1s, -> {owned}, class_name: "Child1"
  has_many :sold_child1s, -> {sold}, class_name: "Child1"

  scope :with_owned_child1s, -> {joins(:owned_child1s)}
  scope :with_sold_child1s, -> {joins(:solid_child1s)}
end

然后,作用域关系使代码更具可读性

Child2.with_owned_child1s.where(....) etc.
于 2015-03-30T12:38:09.030 回答