LoginSignup
0
1

More than 5 years have passed since last update.

ユーザーの認証周りの細かいバリデーション

Posted at

これは何?

認証周りは慎重に記述しなければならない領域のため、
テスト含めて一度ベースとなるバリデーション周りを整理する。

環境

Ruby 2.5.1
Rails 5.2
RSpec 3.8

ログインバリデーション

bundle exec rails g model User name:string email:string

app/models/user.rb
class User < ApplicationRecord
 before_save { self.email = self.email.downcase }

 validates :name, presence: true, length: { maximum: 50 }
 VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
 validates :email, presence: true, length: { maximum: 255 }, format: { with: VALID_EMAIL_REGEX }, uniquneness: { case_sensitive: false }
 has_secure_password
 validates :password, presence: true, length: { minimum: 6 }
end
spec/factories/users.rb
FactoryBot.define do
 factory :user do
  name { "Jo Aoki" }
  sequence(:email) { |n| "jo#{n}@reactcorp.com" }
  password { "password" }
 end
end
spec/models/user_spec.rb
require 'rails_helper'

RSpec.describe User, type: :model  do
 before do
  user_params = FactoryBot.attributes_for(:user)
  @user = User.new(user_params)
 end
 it "should be valid" do
  expect(@user).to be_valid
 end
 it "name should be present" do
  @user.name = ""
  expect(@user).not_to be_valid
 end
 it "name should be proper long" do
  @user.name = "a"*50
  expect(@user).to be_valid
 end
 it "name should not be too long" do
  @user.name = "a"*51
  expect(@user).not_to be_valid
 end
 it "email should be present" do
  @user.email = ""
  expect(@user).not_to be_valid
 end 
 it "email should be proper long" do
  @user.email = "a"*243+"@example.com"
  expect(@user).to be_valid
 end
 it "email should not be too long" do
  @user.email = "a"*244 + "@example.com"
  expect(@user).not_to be_valid
 end
 it "email should be valid format" do
  valid_addresses = %w[user@example.com user_123@foo.jp USER.111@bar.com]
  valid_addresses.each do |valid_address|
   user = FactoryBot.build(:user, email: valid_address)
   expect(user).to be_valid
  end
 end
 it "email should not be invalid format" do
  invalid_addresses = %w[user@example,com user@example abcd_user@example.com.jp user@example_com user@example..com]
  invalid_addresses.each do |invalid_address|
   user = FactoryBot.build(:user, email: invalid_address)
   expect(user).not_to be_valid
  end
 end
 it "email addresses should be unique" do
  duplicate_user = FactoryBot.build(:user, email:@user.email)
  @user.save
  expect(duplicate_user).not_to be_valid
 end
 it "email addresses should be alphabetically unique" do
  user = FactoryBot.create(:user, email: "JO@reactCORP.COM")
  duplicate_user = FactoryBot.create(:user, email: user.email.downcase)
  expect(duplicate_user).not_to be_valid
 end
 it "saves only downcase email" do
  user = FactoryBot.create(:user, email: "JO@reaCTCorp.coM"
  expect(user.reload.email).to eq "jo@reactcorp.com"
 end
 it "password should be present" do
  user = FactoryBot.build(:user, password: ""*10)
  expect(user).not_to be_valid
 end
 it "is valid with a proper length password" do
  user = FactoryBot.build(:user, password: "a"*6)
  expect(user).to be_valid
 end
 it "is invalid with a short length password" do
  user = FactoryBot.build(:user, password: "a"*5)
  expect(user).not_to be_valid
 end
end

注意点

▼ uniquenessの欠点

一意性のバリデーションをかけていたとしても、
ユーザーが二度連続で保存ボタンを押してしまった場合などはuniquenessのバリデーションが効きません。
その解決策としてDBレベルでのuniquenessを担保していれば解決します。

bundle exec rails g migration add_index_to_users_email

db/migrate/hogehoge.rb
class AddIndexToUsersEmail < ActiveRecord::Migration[5.2]
 def change
  add_index :users, :email, unique: true
 end
end

bundle exec rails db:migrate

これにより、uniquenessの解決もされますが、emailカラムにindexが貼られたことになる為、
emailによる検索速度が向上するという副次的なプラスもあります。

▼ has_secure_passwordの効果

  • DBのpassword_digestにハッシュ化したパスワードを保存する
    • 事前にstring型のカラムを用意する必要がある
  • 仮想属性(passwordpassword_confirmation)を作成する
    • 両者が一致しているかどうかの確認もする
    • 存在確認は一応してくれるが、更新時にはバリデーションを通らないので、必ず存在確認のバリデーションを入れる。
  • authenticate(params[:password])メソッドが利用可能
    • 引数のパスワードが一致すればUserオブジェクトを、間違えるとfalseを返す

bundle exec rails g migration add_password_digest_to_users password_digest:string
bundle exec rails db:migrate

ハッシュ化のためにbcryptgemを利用します。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1