🍣

ユニークのvalidatesって必要?

に公開

Railsアプリケーションを開発しているとき、

  • データのユニーク制約ってDBだけにつけておけばいいの?
  • それともvalidatesもつけといた方がいい??

どっちなの?ってなった

問題になったテーブル

※ブログ用に色々改変

# == Schema Information
#
# Indexes
#
#  index_user_item_ratings_on_item_id                (item_id)
#  index_user_item_ratings_on_user_id                (user_id)
#  index_user_item_ratings_on_user_id_and_item_id UNIQUE (user_id, item_id)
#
class UserItemRating < ApplicationRecord
  belongs_to :user
  belongs_to :item

  enum rating: {
    bad: 0,
    good: 1,
    very_good: 2
  }

  # こいつがいるのかいらないのか
  validates :user_id, uniqueness: { scope: :item_id }
end

機能

ユーザがあるitemに対して、評価をつける機能
ただし、同じユーザが一つのitemに対して複数評価をつけられないようにしたい

結論

今回はvalidatesはいらない!
DBのユニークインデックスだけで十分ですねってなった

理由

  • ユニークバリデーションは内部的に SELECT クエリが発行され、DBアクセスが発生する
    • DB側でも UNIQUE INDEX により同じチェックが行われるため 二重チェックになる
  • validates は基本的に DBアクセスなしで事前に検証できることに価値があるが、ユニーク性に関しては DBアクセス前提なのでその利点を活かしにくい

つまり、Railsのvalidates機能を使用するメリットがありませんでしたというお話。

ChatGPTにも聞いてみた

Railsのvalidatesって結局いつ使えばいいんだ?
AIに聞いてみたのでまとめておく。

1. ユーザー入力の検証(フォームバリデーション)

  • 必須チェック(presence)
  • 文字数制限(length)
  • 形式制限(format)
  • 一致チェック(confirmation)
  • 同意確認(acceptance)

2. ビジネスルールの明示と強制

  • 数値制限(numericality)
  • 値の許容・禁止(inclusion / exclusion)
  • 重複チェック(uniqueness ※DB制約と併用)

3. 属性間の依存ロジックの検証

  • 日付の前後関係
  • 条件付き必須(例: プレミアムユーザーは電話番号必須)
  • カスタムバリデーション(validate :method_name

4. UX向上(エラーメッセージ表示)

  • フォームにバリデーションメッセージを表示できる
  • エラー箇所のフィールドに視覚的にフィードバックできる

5. APIレスポンスに適切なエラーを返す

  • 例: 422 Unprocessable Entity + JSONでエラー詳細

6. モデル設計の明確化

  • バリデーションがあることで、モデルの使い方がわかりやすくなる
  • テストやコードレビューの助けになる

validates を使うか判断するためのチャート

まとめ

プロダクトの設計思想によってもどうすべきかが変わってくると思うので、今回の結論が他のプロダクトでも当てはまるかはまた別のお話

Discussion