【rails】enumのレコード登録数をバリデーションで制限する方法


はじめに

開発を行っているとenumを使って、データを分ける場合があると思います。
enumで分けたデータに対してそれぞれレコードの登録数を制限する実装をしたのでメモとして残しておきます。

開発環境

Rails 6.0.3
Ruby 2.7.1

テーブル

今回は下記のようなUsersテーブルを想定しています。
性別(sex)はenumでman/femaleのどちらかしか選択できないようにしています。

name sex(enum)
ユーザー1 man
ユーザー2 female

レコード数を制限する方法

models/user.rbにメソッドを作成し、man/femaleそれぞれのレコード数を確認して、もし制限数(10件)を超えていればエラーを追加します。
on: :createを記載しないと毎回バリデーションが適用され、編集できなくなってしまうので忘れないよう!
(私はここに気づかず編集の際にエラーが発生してしまいました。)

user.rb
class User < ApplicationRecord
  REGISTER_LIMIT_COUNT = 10 # 定数として登録数を管理

  enum sex: { man: 0, female: 1 }

  validate :limit_user_register_count, on: :create  # 作成したメソッドでバリデーション

  def limit_user_register_count
    if self.sex == "man" && man.count >= REGISTER_LIMIT_COUNT # enumがman かつ manのレコード数が制限を超えている
        errors.add(:user, "man count is over") # エラーを追加
    elsif self.sex == "female" && female.count >= REGISTER_LIMIT_COUNT
        errors.add(:user, "female count is over")
    end
  end
end

Rspecでバリデーションを確認する方法

user_spec.rb
require 'rails_helper'

RSpec.describe Guide, type: :model do
  context 'データを11個以上登録する場合' do
    before { create_list(:user, 10, sex: 'man') } # manのデータをを10人分作成

    it 'エラーメッセージを返すこと' do
      man = build(:user, sex: 'man') # 11人目をbuildする(バリデーションがかかるのでcreateは不可)
      man.valid?                     # validすることでcreateしようとしてvalidationが走り、エラーが追加される
      expect(man.errors[:user]).to eq('man count is over')
    end
  end
end
factories/users.rb
FactoryBot.define do
  factory :user do
    name { Faker::Name.name }
    sex { 0 }
  end
end