Rails で has_many::through 関連付けに外部キーを設定するにはどうすればよいですか?
概要
Item と ItemsBelonging という 2 つのテーブルがあります。アイテム間にツリー関係を作成しようとしています。アイテムのすべての子孫に対して、アイテムと子孫アイテムを結合する item_belonging を作成します。
Item {
id:,
...
}
ItemBelonging {
id:,
item_id:,
descendant_id:,
...
}
item.descendants を正常に呼び出して、項目のすべての子孫を受け取ることができます。次のような関係を設定しました。
class ItemBelonging < ApplicationRecord
belongs_to :descendant, :class_name => 'Item'
...
end
class Item < ApplicationRecord
has_many :descendants, :through => :item_belongings, :source => :descendant
...
end
問題は、同じ itemBelonging 関係を使用して item.ancestors を呼び出してアイテムのすべての祖先を取得できるようにしたいことです。私はこれを次のように行うことができます:
def ancestors
Item.joins(:item_belongings).where("item_belongings.descendant_id = ?", id)
end
しかし、has_many/belongs_to を使用してこの関係を作成するにはどうすればよいでしょうか?これは動作しません:
class ItemBelonging < ApplicationRecord
belongs_to :descendant, :class_name => 'Item'
belongs_to :ancestor, :class_name => 'Item', :foreign_key => :item_id
...
end
class Item < ApplicationRecord
has_many :descendants, :through => :item_belongings, :source => :descendant
has_many :ancestors, :through => :item_belongings, :source => :ancestor, :foreign_key => :descendant_id
...
end
私の最終目標は、Item.includes(:descendants) と Items.includes(:ancestors) を呼び出せるようにすることです。先祖関係をうまく機能させるにはどうすればよいですか?
解決策
ancestry gem を使用すると、このような DSL を簡単に使用できます
class Item < ApplicationRecord
has_ancestry
end
そして、いくつかのレコードを作成します
parent = Item.create
first_child = Item.create(parent: parent)
second_child = Item.create(parent: parent)
first_child_child = Item.create(parent: first_child)
そして、そのようなメソッドをすぐに使用できます
parent.children # => [first_child, second_child]
parent.descendants # => [first_child, second_child, first_child_child]
first_child.siblings # => [first_child, second_child]
first_child.subtree # => [first_child, first_child_child]
first_child_child.parent # => first_child
first_child_child.root # => parent
first_child_child.ancestors # => [parent, first_child]
first_child_child.path # => [parent, first_child, first_child_child]