rails で複合項目で一意性チェックを行う方法を備忘録として残しておく
環境
- ruby: 3.0.5
- rails: 6.1.7
実際のコード
[ER 図]
[model]
uniqueness + scope で validate を行う
class Book
has_many :book_categories, dependent: :destroy
has_many :categories, through: :book_categories
end
class BookCategory
belongs_to :book
belongs_to :category
# book_id + category_id で一意かどうかをチェック
validates :book_id, uniqueness: { scope: :category_id }
end
class Category
has_many :book_categories
has_many :books, through: :book_categories
end
[migrate]
unique index を追加する
class CreateBookCategoriess < ActiveRecord::Migration[6.1]
def change
create_table :book_categories do |t|
t.references :book, foreign_key: true
t.references :category, foreign_key: true
t.timestamps
end
add_index :book_categories, [:book_id, :category_id], unique: true
change_table_comment :book_categories, '本のカテゴリー'
end
end
[rspec]
FactoryBot + shoulda-matchers 導入している場合
require 'rails_helper'
describe BookCategory, type: :model do
describe 'validations' do
subject { FactoryBot.build(:book_category) }
context 'book_id' do
it { is_expected.to validate_uniqueness_of(:book_id).scoped_to(:category_id) }
end
end
end