返回ActiveRecord关系中的名称以及外键id

时间:2017-07-07 20:27:06

标签: ruby-on-rails ruby activerecord

我有一个子组件模型,可以属于其他子组件。我的模型看起来像这样:

class SubComponent < ApplicationRecord
  belongs_to :parent, class_name: "SubComponent", foreign_key: "parent_sub_component_id", optional: true
  has_many :child_sub_components, class_name: "SubComponent", foreign_key: "parent_sub_component_id"

  validates_presence_of :name
end

此模型非常简单,它有name字段和parent_sub_component_id,顾名思义是另一个id的{​​{1}}。

我想生成一个返回所有SubComponent(包含SubComponentsidname)的查询,但也包含实际内容它的名称是parent_sub_component。

这看起来应该很简单,但对于我的生活,我无法弄清楚如何去做。我希望在数据库中完成此查询,而不是在Ruby中执行每个循环或类似的事情。

编辑:

我希望输出看起来像这样:

parent_sub_component_id

2 个答案:

答案 0 :(得分:1)

如果您使用each

,则可以使用includes循环有效地执行此操作
SubComponent.all.includes(:parent).each do |comp|
  comp.parent.name  # this gives you the name of the parent
end

includes做了什么预取指定的关联。也就是说,ActiveRecord将查询所有子组件,然后在单个查询中也拉下这些子组件的所有父组件。当您随后在循环中访问comp.parent时,已经加载了关联的父级,因此这不会导致所谓的 N + 1查询

AR将自动为您生成的查询将如下所示:

SELECT `subcomponents`.* FROM `subcomponents`
SELECT `subcomponents`.* FROM `subcomponents` WHERE `subcomponents`.`id` IN (1, 3, 9, 14)

如果您需要在where条件下使用父级名称,includes将无效,您必须使用joins来实际生成SQL {{1 }}

答案 1 :(得分:0)

这是未经测试的,但是应该让你从正确的方向开始,你可以通过做类似

的方式在Arel中做到这一点
def self.execute_query
  parent_table = Arel::Table.new(:sub_component).alias
  child_table = Arel::Table.new(:sub_component)

child_table.join(parent_table, Arel::Nodes::OuterJoin).on(child_table[:parent_sub_component_id].eq(parent_table[:id]).project(child_table[:id], child_table[:name], parent_table[:id], parent_table[:name])
end

这会产生类似

的查询
SELECT "sub_component"."id", "sub_component"."name", "sub_component_2"."id", "sub_component_2"."name" FROM "sub_component" LEFT OUTER JOIN "sub_component" "sub_component_2" ON "sub_component"."parent_sub_component_id" = "sub_component_2"."id"

通过查看Rails/Arel并且可能需要一些工作,这只是我的头脑,但查询看起来我期待什么,这应该让你去。