前提
Rails 6.0.3.1
ruby 2.6.3
RSpec 3.6
一意性のテストにて
メールアドレスのバリデーションをRSpec
でテストをしていました。
以下がバリデーションです。
validates :email, presence: true,
length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
今回引っ掛かったのが、ここ。
app/models/user.rb
uniqueness: { case_sensitive: false }
下記が、メールアドレスの一意性を確かめるテスト内容になります。
spec/models/user_spec.rb
it "is invalid if email is not uniqueness " do
duplicate_user = @user.dup
duplicate_user.email = @user.email.upcase
@user.save!
expect(duplicate_user).to be_invalid
end
it "confirm email is saved in lowercase" do
@user.email = "Test@examplE.coM"
@user.save!
expect(@user.reload.email).to eq 'test@example.com'
end
そもそもcase_sensitive: falseをきちんと理解していなかった
Active Record バリデーション
リファレンスを参照してみると、
"大文字小文字の違いを確認する制約をかけるかどうかも定義"
とありました。
ちなみにデフォルトでは、true
となっていますが、一部のデータべースでは大文字小文字を区別しない設定となっているため、rails側でオプションとしてcase_sensitive: false
を指定してあげるということみたいです。
エラーをみてみる
Failures:
1) User email confirm email is saved in lowercase
Failure/Error: expect(@user.reload.email).to eq 'test@example.com'
expected: "test@example.com"
got: "Test@examplE.coM"
(compared using ==)
# ./spec/models/user_spec.rb:91:in `block (3 levels) in <main>'
# -e:1:in `<main>'
Finished in 3.27 seconds (files took 2.25 seconds to load)
33 examples, 1 failure
Failed examples:
rspec ./spec/models/user_spec.rb:88 # User email confirm email is saved in lowercase
期待していたのは、"test@example.com"
ですが、得られた結果は got: "Test@examplE.coM"
だよと言っています。
要は、大文字が混ざっていても、それを小文字に変換する処理が起きていない状態ですね。
そのため、小文字に変換する処理
を追記してあげます。
app/models/user.rb
class User < ApplicationRecord
# 追記
before_save { email.downcase! }
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
# 中略
validates :email, presence: true,
length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
# 中略
% bin/rspec
Running via Spring preloader in process 66678
.................................
Finished in 3.21 seconds (files took 2.7 seconds to load)
33 examples, 0 failures
無事パスしました!!!!