#Railsの自己結合②
はじめに
前回の続きです。Rails Developers MeetUpでお話聞きながら書いてます。
##Railsで自己結合やってみる##
前回、自己結合が何かイメージできたところで実装です。
親子関係のあるPersonクラスを元に考えていきます。
20181208054943_create_people.rb
class CreatePeople < ActiveRecord::Migration[5.1]
def change
create_table :people do |t|
t.string :name
t.references :person, foreign_key: true
t.timestamps
end
end
end
Personモデルを作ります。
references
で参照するカラムを作成し、外部キー制約も指定しています。
rails db:migrate
します。
schema.rb
ActiveRecord::Schema.define(version: 20181208054943) do
create_table "people", force: :cascade do |t|
t.string "name"
t.integer "person_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["person_id"], name: "index_people_on_person_id"
end
Personテーブルが作成されました。reference
では自動でperson_idを作成してくれます。index
も自動で貼ってくれます。
person_id
を用いて親を参照できるようにします。
Person.rb
class Person < ApplicationRecord
has_many :children, :class_name => 'Person', :foreign_key => 'person_id', dependent: :destroy
belongs_to :parent, :class_name => 'Person', :foreign_key => 'person_id', optional: true
end
1対Nの関係になりますので、children
を多数持つのでhas_many :children
、
その逆でparent
は一人なので、belongs_to :parent
となります。
:class_name
はもちろんPerson
ですね。外部キーはperson_id
を指定します。
dependant
によって親が消えたら子も消えるようにしてます。
p = Person.create(name: "aaa")
p.children = [Person.create(name: "bbb")]
p
#=> #<ActiveRecord::Associations::CollectionProxy [#<Person id: 1, name: "aaa", person_id: 2, created_at: "2018-12-08 14:54:37", updated_at: "2018-12-08 14:54:37">]>
これで自己結合は完了です。実際に親を参照できるか試してみましょう。
p.children.first.parent
#=>#<Person id: 1, name: "aaa", person_id: nil, created_at: "2018-12-08 14:52:26", updated_at: "2018-12-08 14:52:26">
これで自己結合は完璧ですね!