重用查询中具有与同一STI表的has_many关系的范围



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

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

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

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中已有的作用域。

您可以在不使用任何具有两个作用域关系的第三方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:child1,您将使用以下查询

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.

相关内容

  • 没有找到相关文章

最新更新