Rails - has_many & belongs_to関係を既存のモデルに追加

More than 3 years have passed since last update.


既存のモデル


  • Moving

  • Room

上記のモデル間にhas_many & belongs_to関係を追加する。


やり方


各モデルのテーブルにお互いのidをforeign_keyとして追加し、マイグレートする

$ rails g migration add_room_to_movings room:references

下記のマイグレーションが生成される。間違いがないか確認。


20150725142417_add_room_to_movings.rb

class AddRoomToMovings < ActiveRecord::Migration

def change
add_reference :movings, :room, index: true, foreign_key: true
end
end

$ rails g migration add_moving_to_rooms moving:references

下記のマイグレーションが生成される。間違いがないか確認。


20150725142845_add_moving_to_rooms.rb

class AddMovingToRooms < ActiveRecord::Migration

def change
add_reference :rooms, :moving, index: true, foreign_key: true
end
end

$ rake db:migrate


has_manybelongs_toを関係するモデルのクラスに追加


moving.rb

class Moving < ActiveRecord::Base

...
has_many :rooms, dependent: :destroy
...


room.rb

class Room < ActiveRecord::Base

...
belongs_to :moving
...

これで完了。


コンソールで思い通りの振る舞いになっているか確認

$ rails console --sandbox

色々試す。本当にこれで良いのかここでよく考える。場合によってはhas_many, throughを使えばもっと効率よくデータの管理ができるかもしれない。


気が変わったら、早いうちにやり直す(許されるなら)

$ rails destroy migration add_moving_to_rooms moving:references

invoke active_record
remove db/migrate/20150725142845_add_moving_to_rooms.rb

$ rails destroy  migration add_room_to_movings room:references

invoke active_record
remove db/migrate/20150725142417_add_room_to_movings.rb

忘れずにhas_manybelongs_toをモデルのクラスから取り除くこと。

以下のタスクでschemaを更新する。

$ bundle exec rake db:drop

$ bundle exec rake db:create
$ bundle exec rake db:migrate
$ bundle exec rake db:seed


has_many, throughに変更することにした

以下のコマンドで中間テーブルのクラスとマイグレーションをつくる。

rails g model MovingRoom moving_id:integer room_id:integer


20150725172522_create_moving_rooms.rb

class CreateMovingRooms < ActiveRecord::Migration

def change
create_table :moving_rooms do |t|
t.integer :moving_id
t.integer :room_id

t.timestamps null: false
end
end
end



moving_room.rb

class MovingRoom < ActiveRecord::Base

end

中間テーブルのクラスにbelongs_toを追加し、モデルを関連させる。


moving_room.rb

class MovingRoom < ActiveRecord::Base

belongs_to :moving
belongs_to :room
end

各モデルクラスにhas_many...through...を追加し、中間テーブル経由でお互いにアクセスできるようにする。

class Moving < ActiveRecord::Base

...
has_many :moving_rooms, dependent: :destroy
has_many :rooms, through: :moving_rooms
...

class Room < ActiveRecord::Base

...
has_many :moving_rooms, dependent: :destroy
has_many :movings, through: :moving_rooms
...

効率よくクエリできるようIndexを追加


20150726014749_add_index_to_moving_rooms.rb

class AddIndexToMovingRooms < ActiveRecord::Migration

def change
add_index :moving_rooms, :moving_id
add_index :moving_rooms, :room_id
add_index :moving_rooms, [:moving_id, :room_id], unique: true
end
end

以上。


参考資料