4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ログインフォームにバリデーションをつける

Last updated at Posted at 2019-01-22

はじめに

ログインフォームにフォームオブジェクトを使ってバリデーションをつけます

準備

とりあえず最初の設定とか準備

rails new login_form_validate
rails g model user email:string password_digest:string
rails db:migrate
rails g controller users index new 
rails g controller sessions new 

gemの設定

gem 'bcrypt', '~> 3.1.7'
gem 'simple_form'
gem 'bootstrap'
gem 'popper_js'
gem 'tether-rails'
gem 'jquery-rails'
gem 'validates_email_format_of'

routes.rb

Rails.application.routes.draw do
  resources :sessions
  resources :users
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

users_controller

class UsersController < ApplicationController

  def index 
  end 

  def new
    @user = User.new
  end

  def create 
    @user = User.create(user_params)
    if @user.save 
      redirect_to users_path 
    else 
      render :new 
    end 
  end 

  private 

  def user_params
    params.require(:user).permit(:email,:password,:password_confirmation)
  end 
end

users_views

new.html.erb
<br>
<br>
<br>
<br>
<div class="container">
    <%= simple_form_for(@user) do |f| %>
        <div class="form-group">
            <%= f.input :email %>
        </div>
        <div class="form-group">
            <%= f.input :password %>
        </div>
        <div class="form-group">
            <%= f.input :password_confirmation %>
        </div>
        <%= f.submit %>
    <% end %>
</div>

i18nの設定

config/application.rbに

config.i18n.default_locale = :ja
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s]

を追加

config以下にdefault,models,viewsフォルダ作成

default以下にja.yml作成し

これを張り付ける

models以下にuserフォルダ作成しその下にja.yml作成し

ja:
  activerecord:
    models:
      user: ユーザー
    attributes:
      user:
        email: メールアドレス
        password: パスワード

viewsフォルダ以下にja.ymlを作成して

ja: 
  helpers:
    submit:
        create: '登録する'
        update: '更新する'
        submit: '保存する'
  simple_form:
    required:
        html: '<abbr class="nec">必須</abbr>'
    labels:
      user:
        email: 'メールアドレス'
        password: 'パスワード'
    hints:
      user:
        email: 'サインインするメールアドレスを入力してください'
        password: '半角英数字のみ使えます'
    placeholders:
      user:
        email: 'メールアドレス'
        password: 'パスワード'

これを張り付ける

バリデーションを設定

models/user.rbに

user.rb

has_secure_password

    validates :email, presence: true 
    validates :email, :email_format => {:message => '正しいメールアドレスを入力してください'}
    validates :password, presence: true 

これを追加

これで

qiita-form.png

こんな感じになってとりあえずuserを登録できるはず

本題

formObjectを使ってログインフォームにバリデーションを追加します

まずappいかにformsフォルダを作成その下に

session.rbを作成します

そして中身を

session.rb

class Session
    include ActiveModel::Model 

    attr_accessor :email, :password 

    validates :email, presence: true 
    validates :password, presence: true 

    def save 
        return false if invalid?
        true
    end 
end

これを追加。

まずActiveModel::Modelをインクルードしていることでバリデーションとか使える。

attr_accessorは必要で使うカラムを書いておく。

今回の場合はemailとpassword

saveに関しては.saveされるときに呼び出されてもしvalidatesに引っかかった場合はfalseがかえりそうでなければtrueがかえる。

この場合明示的にtrueを書いておかなきゃだめ。

次にsessions_controller

class SessionsController < ApplicationController
  def new
    @login = Session.new
  end

  def create 
    @login = Session.new(email: params[:session][:email], password: params[:session][:password])
    if @login.save && (@user = User.find_by(email: @login.email)) && @user.authenticate(@login.password)
      redirect_to users_path
    else 
      render :new 
    end 
  end 
end

こんな感じになる。

先ほど作ったsessionクラスを使っている。

ちなみに基本的にform_objectのクラスの名前は何でも大丈夫ですが今回はsessionにしているのには理由があってこうすることでform_forの時にsessionというクラス名からsession_pathが自動的に作られるからです。

例えばloginというクラス名のform_objectを作ってしまうとログインフォームで


<%= simple_form_for(@login) do |f| %>

<% end %>

としたときに自動生成されるパスはlogin_path method: :postつまり/logins/createになるからです。

if @login.save && (@user = User.find_by(email: @login.email)) && @user.authenticate(@login.password)

ここでfalseになるとrender :newが実行されます。

この時にちゃんとエラーメッセージが表示されます。

ちなみこのままだとエラーメッセージが英語になっていると思います。

これを英語にするためには

locals/models以下にsessionフォルダを作成し以下にja.ymlを作成

中身を


ja:
  activemodel:
    attributes:
        session:
            email: メールアドレス
            password: パスワード

とすれば日本語になってくれます。

カスタムバリデーション

form_objectにカスタムバリデーションを追加します

emailが実在しなかったらemailは使われていないとエラーを出し、emailは存在するものだがパスワードが存在しないものの場合はemailではエラーを出さずpasswordのところでエラーを出すようにします。

コードはこんな感じになります。

class Session
    include ActiveModel::Model 

    attr_accessor :email, :password 

    validates :email, presence: true 
    validates :password, presence: true 
    validate  :true_email
    validate  :true_password


    def true_email
        errors.add(:email, "は使われていません。") unless User.find_by(email: email)
    end 

    def true_password
        @user = User.find_by(email: email)
        if @user 
            errors.add(:password, "は正しくありません。") unless @user.authenticate(password)
        else  
            errors.add(:password, "は正しくありません。")
        end 
    end 

    def save 
        return false if invalid?
        true
    end 
end

true_emailとtrue_passwordというバリデーションを作成しています。

エラーを発生させる場合はerrors.addで発生させます。

ちなみにerrors.add(:base, "")という書き方もできて全体のエラーとして表示したい場合に使えます。

ですがsimple_formでは表示されないので手を加える必要があります。

viewに@login.errors[:base]みたいな感じで表示することができます

終わり:sunny:

4
5
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
4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?