こんにちは、nishi_talk(@nishi_talk)です。
Railsでリレーションを貼った投稿を作成することが多いですが、同じテーブルのリレーションを別でもたせる方法をご紹介します!
ちょっと特別な案件かもしれないが、ひとつの投稿に対して、同じリレーション先を登録必要があったので、対応した方法を紹介。
※既存案件だったので、DBをあまり触らず対応したので、他にもベストプラクティスがあると思うけど
やりたいこと
例えば、ひとつの投稿に対して編集者が投稿した月と管理者がその投稿を編集した月を分けて管理する必要があった。既に編集者が投稿した月にhas_manyでリレーションしていた。
後日、管理者がその投稿を編集した月を追加する。
posts(1) → monthlies(多)
mysql> show columns from posts; +-----------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------------+--------------+------+-----+---------+----------------+ | id | bigint(20) | NO | PRI | NULL | auto_increment | | monthly_id | bigint(20) | YES | MUL | NULL | | +-----------------+--------------+------+-----+---------+----------------+ mysql> show columns from monthlies; +-------------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------------+--------------+------+-----+---------+----------------+ | id | bigint(20) | NO | PRI | NULL | auto_increment | | data | varchar(255) | YES | | NULL | | +-------------------+--------------+------+-----+---------+----------------+
モデル
railsのモデルはこんな感じで、monthliesに対して、postが紐付いてる構造です。
app/models/monthly.rbに以下の記述をします。
class Monthly < ApplicationRecord has_many :posts end
app/models/post.rbに以下の記述をします。
class Post < ApplicationRecord belongs_to :monthly end
カラムを追加
まずは「posts」に「fix_monthly」を追加します。
fix_monthlyはpostのリレーションなので、referenceを指定します。
$ rails g migration AddPostRefToMonthly
db/migrate/xxx_add_monthly_ref_to_post.rbに以下の記述をします。
class AddMonthlyRefToPost < ActiveRecord::Migration[5.2] def change add_reference :posts, :fix_monthly end end
作成できたら、migrateします。
$ rails db:migrate
データベースが変更されたか確認
postのテーブルにfix_monthly_idが追加されたか確認します。
mysql> show columns from posts; +-----------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------------+--------------+------+-----+---------+----------------+ | id | bigint(20) | NO | PRI | NULL | auto_increment | | monthly_id | bigint(20) | YES | MUL | NULL | | | fix_monthly_id | bigint(20) | YES | MUL | NULL | | +-----------------+--------------+------+-----+---------+----------------+ mysql> show columns from monthlies; +-------------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------------+--------------+------+-----+---------+----------------+ | id | bigint(20) | NO | PRI | NULL | auto_increment | | data | varchar(255) | YES | | NULL | | +-------------------+--------------+------+-----+---------+----------------+
これで一つの投稿に同じリレーションを貼ることができました。