Bookmarkモデルは多対多の関係であるUserモデルとDiaryモデルの中間テーブルの役割を担います。今回作成するBookmarksテーブルのアソシエーションはこのようになっています。user_iddiary_idを外部キーとして持っています。

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/db23ba66-4305-4965-a6e5-96a79c25271a/_2021-06-03_21.35.25.png

Bookmarkモデルを作成

まず最初にBookmarksモデルを作成します。

Sayo-MacBook-Pro:emoji_diary SAYO$ bundle exec rails generate model Bookmark user:references diary:references
Running via Spring preloader in process 39970
      invoke  active_record
      create    db/migrate/20210603130042_create_bookmarks.rb
      create    app/models/bookmark.rb

作成されたマイグレーションファイルに必要な制約を追加します。

class CreateBookmarks < ActiveRecord::Migration[6.1]
  def change
    create_table :bookmarks do |t|
      t.references :user, null: false, foreign_key: true
      t.references :diary, null: false, foreign_key: true

      t.timestamps
    end
    add_index :bookmarks, [:user_id, :diary_id], unique: true
  end
end

user_iddiary_idのunique制約は、user_idboard_idの組み合わせがuniqueであることを示しています。これはユーザーが同じ日記をお気に入り登録しないようにするためです。この設定が終わったらrails db:migrateを行います。

Sayo-MacBook-Pro:emoji_diary SAYO$ bundle exec rails db:migrate
== 20210603130042 CreateBookmarks: migrating ==================================
-- create_table(:bookmarks)
   -> 0.3564s
-- add_index(:bookmarks, [:user_id, :diary_id], {:unique=>true})
   -> 0.1609s
== 20210603130042 CreateBookmarks: migrated (0.5174s) =========================

バリデーション

データベースではuser_iddiary_idにnull制約とunique制約をかけました。それを踏まえてモデルにバリデーションを追加していきます。

まず最初はBookamarkモデルです。belongs_toオプションを設定した場合に、対象カラムに対するpresence: trueは自動で設定されるので不要となります。user_idのバリデーションは、user_idに対して、diary_idはuniqueな関係であるということを意味しています。

class Bookmark < ApplicationRecord
  belongs_to :user
  belongs_to :diary

  validates :user_id, uniqueness: { scope: :diary_id }
end

アソシエーション

次に中間テーブルであるBookmarkモデルとUserモデル、Diaryモデルのアソシエーションを定義していきます。

まず最初にDiaryモデルにアソシエーションを追加します。

class Diary < ApplicationRecord
  has_many :bookmarks, dependent: :destroy
end

各日記はたくさんのブックマークをもつことが出来ます。日記が消されるとブックマークも一緒に消えます。