2017-07-07 52 views
1

沿着我有一个子组件模型,它可以属于其他子组件。我的模型是这样的:在ActiveRecord的关系返回名称与外键ID

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场和顾名思义是另一个SubComponentid一个parent_sub_component_id

我想生成返回所有SubComponents的(他们idnameparent_sub_component_id),而且还包括它的实际名称是parent_sub_component查询。

这似乎应该是很简单,但对我的生活我无法弄清楚如何做到这一点。我想要在数据库中完成这个查询,而不是在Ruby中做每个循环或类似的事情。

编辑:

我想对于输出是这个样子:

#<ActiveRecord::Relation [#<SubComponent id: 1, name: "Parent Sub", parent_sub_component_id: nil, parent_sub_component_name: nil created_at: "2017-07-07 00:29:37", updated_at: "2017-07-07 00:29:37">, #<SubComponent id: 2, name: "Child Sub", parent_sub_component_id: 1, parent_sub_component_name: "Parent Sub" created_at: "2017-07-07 00:29:37", updated_at: "2017-07-07 00:29:37">]>

+0

你的意思是一个特定的父组件的每子,以及所有的子子,不管他们是在层次结构中有多深?如果不是,你能给我们一个你想达到的例子输出吗? –

+0

子组件只会有一个父类,所以我希望得到的是父母的名字与它的ID一起。 – quicklikerabbit

回答

1

如果使用includes你可以这样做有效地使用each环:

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 JOIN

0

这是未经测试,但应该让你在正确的方向开始,你可以这样做在阿雷尔通过执行类似

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并可能需要一些工作,但查询看起来我期望什么,这应该让你去。

+0

我真的很想能够在没有宝石的情况下做到这一点。这看起来像ActiveRecord应该能够做到的。 – quicklikerabbit

+0

默认情况下,Arel与Rails打包在一起。这是ActiveRecord在幕后使用的。 –

+0

ActiveRecord(至少最近的版本)使用Arel来生成他们的查询 –