はじめに
ログインフォームにフォームオブジェクトを使ってバリデーションをつけます
準備
とりあえず最初の設定とか準備
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
<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に
has_secure_password
validates :email, presence: true
validates :email, :email_format => {:message => '正しいメールアドレスを入力してください'}
validates :password, presence: true
これを追加
これで
こんな感じになってとりあえずuserを登録できるはず
本題
formObjectを使ってログインフォームにバリデーションを追加します
まずappいかにformsフォルダを作成その下に
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]みたいな感じで表示することができます
終わり