ひーろのアウトプットブログ

プログラミングの学習記録と開発日記です

MySQLとバリデーションにおけるユニーク制約の違い

railsでアプリを作成していたところ、MySQLとvalidatesのユニーク制約で想定していなかった挙動をしました。

前提

ruby: 2.6.6
rails: 6.0.3.5

内容

userテーブルを作成し、ユニーク制約をかけました。

$ rails g model User name:string
class CreateUser < ActiveRecord::Migration[6.0]
  def change
    create_table :users do |t|
      t.string :name, null: false

      t.timestamps
    end
    add_index :users, :name, unique: true # ユニーク制約追記
  end
end
$ rails db:migrate
class User < ApplicationRecord
  validates :name, presence: true
  validates :name, uniqueness: true
end

一旦このバリデーションをかけました。
uniqueness: trueのバリデーションは大文字と小文字を区別するはずなので’aaaaaa’と’AAAAAA’というUserを試しにrails consoleで登録しようとしたところ、後者の登録時に、

ActiveRecord::RecordNotUnique: Mysql2::Error: Duplicate entry 'AAAAAA' for key 'index_users_on_name'

というエラーが発生しました。

解決策

どうやらMySQLでは大文字と小文字を区別しない、というのが標準の挙動だったようです。 今回は大文字と小文字を区別しない設計にしたかったのでバリデーションを変更します。

class User < ApplicationRecord
  validates :name, presence: true
  validates :name, uniqueness: true
  # case_sensitive: falseで大文字と小文字の区別をしなくなる
end

このように書き換えたあと先ほどと同じUser名を登録しようとしたところ、バリデーションが利きROLLBACKされました。