3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Rails】正しいmany-to-manyテーブルの作り方

Last updated at Posted at 2019-12-28

環境

  • Rails 5.2.2

やりたいこと

  • FistNameクラス(first_namesテーブル)とLastNameクラス(last_namesテーブル)をmany-to-manyで繋ぐFullNameクラス(full_namesテーブル)を作りたい。

手順

rails g model の実行

rails generate model FullName first_name:references last_name:references

生成されるマイグレーションファイル

class CreateFullNames < ActiveRecord::Migration[5.2]
  def change
    create_table :full_names do |t|
      t.references :first_name, foreign_key: true
      t.references :last_name, foreign_key: true

      t.timestamps
    end
  end
end

マイグレーションファイルを編集

  • t.referencesbelongs_toreferencesのalias)はindexも作成してくれます。
    • foreign_key: trueがあれば、外部キー制約もつけてくれます。
  • t.referencesを使いつつ、中間テーブルでは、以下の通り変更します。
    • 複合キーでunique制約を張ります。(※1)
    • 上記のunique制約でfirst_name_idに対するindexも張られるため、index: falseを指定します。(※2)
    • last_name_idに対するindexも不要であれば、index: falseを指定します。
class CreateFullNames < ActiveRecord::Migration[5.2]
  def change
    create_table :full_names do |t|
      t.references :first_name, foreign_key: true, null: false, index: false # (※2)
      t.references :last_name, foreign_key: true, null: false

      t.timestamps
    end

    add_index :full_names, [:first_name_id, :last_name_id], unique: true # (※1)
  end
end

モデル

マイグレーションを実行して生成される中間テーブルのモデル

app/models/full_name.rb
class FullName < ApplicationRecord
  belongs_to :first_name
  belongs_to :last_name

  # DB レベルでは外部キー制約、複合ユニークインデックスが付いているため、以下の validates が無くても
  # 意図しないデータが保存されることはありません(なので、無くても大丈夫です)。
  # 但し、その場合 DB のエラーが返されます。
  # Rails のエラーを返したい時は、validates をつけましょう。
  # 但し、Rails の処理のほうが遅いはずなので、メッセージへのこだわりが無く、スピード重視の場合はここの validates は外してください。
  #
  # ※上記については、belongs_to のデフォルトで required: true となっているため、presence: true の validates については、
  #  Rails レベルで担保されそうです(エラー内容は validates ~ presence: true と belongs_to で異なるかもしれませんが)。
  validates :first_name_id, presence: true
  validates :last_name_id, presence: true
  validates :first_name_id, uniqueness: { scope: :last_name_id }
end

その他のモデル

app/models/first_name.rb
class FirstName < ApplicationRecord
  has_many :full_names, dependent: :destroy
  has_many :last_names, through: :full_names
end
app/models/last_name.rb
class LastName < ApplicationRecord
  has_many :full_names, dependent: :destroy
  has_many :first_names, through: :full_names
end
3
5
3

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
3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?