2017-07-07 30 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來生成他們的查詢 –

相關問題