LoginSignup
6
3

More than 5 years have passed since last update.

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">

これで自己結合は完璧ですね!

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3