JOIN ON ...和在ActiveRecord

时间:2015-11-15 03:39:41

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

请注意,这不是关于向关联添加WHERE条件的问题,而是关于在使用eager_load时如何更改JOIN子句的相当高级的问题。

假设我有这些模型

class Parent
  has_many :children
  have_many :grades, through: :children
end

class Child
  belongs_to :parent
end

class Grade
  belongs_to :child
end

所以要急切地加载我会做的父母:

Parent.eager_load(:grades)

但是,如果我想要所有的父母 - 但只是急切地加载最高得分如此:

LEFT OUTER JOIN grades ON grades.child_id = children.id AND grades.level = 'A+'

我尝试过使用includes(:children).joins("LEFT OUTER JOIN grades ON grades.child_id = children.id AND grades.level = 'A+'"),但由于Rails没有构建关联对象,因此会为每个父对象产生额外的查询。

我没有找到任何关于将eager_load与自定义SQL字符串一起使用的引用,并且dug through the source没有得到任何更明智的提示。

2 个答案:

答案 0 :(得分:1)

修改

这并不能解决所述问题。

您无法通过调用eager_load来改变生成的JOIN。 WHERE子句是您唯一的选项,它与JOIN上的条件具有完全相同的效果。就在这里,即使你不想要它:

Parent.eager_load(:grades).where("grades.level = 'A+'")

答案 1 :(得分:1)

如果我是对的,你只想急切加载关联的子集。好吧,为了做到这一点,你需要超越铁轨。您基本上可以创建另一个关联,例如" highest_grade"使用ruby lambda中的where子句获取等级A +的等级。这可以通过使用以下代码片段来实现

class Parent
  has_many :children
  has_many :grades, through: :children
  has_many :highest_grade, ->{where(level: 'A+')}, class_name: "Grade", through: :children
end

现在您需要急切加载highest_grade关联。

 Parent.eager_load(:highest_grades)

这将基本上加载所有父母以及只有等级为A +的成绩。

它会生成以下查询。

 SQL (0.3ms)  SELECT `parents`.`id` AS t0_r0, `parents`.`created_at` AS    t0_r1, `parents`.`updated_at` AS t0_r2, `grades`.`id` AS t1_r0,    `grades`.`child_id` AS t1_r1, `grades`.`created_at` AS t1_r2, `grades`.`updated_at` AS t1_r3, `grades`.`level` AS t1_r4 FROM `parents` LEFT OUTER JOIN `children` ON `children`.`parent_id` = `parents`.`id` LEFT OUTER JOIN `grades` ON `grades`.`child_id` = `children`.`id` AND `grades`.`level` = '

如果您想了解这是如何工作的。请使用this link as a reference