Railsチュートリアル第8章で作成したログインフォームは、ログインに失敗するとフォームに入力した値がリセットされてしまいます。
そこで、ログイン失敗時にフォームに入力した値(メールアドレス)を保持する方法についてまとめました。
開発環境
- Ruby 3.1.2
- Ruby on Rails 7.0.3
- M1 Macbook Air 2020
- mac OS Monterey (ver. 12.4)
- ターミナル bash (Rosetta 2 使用)
【現状】ログイン失敗時の挙動
現状(Railsチュートリアル第8章で作成したログインフォーム)のログイン失敗時の挙動は以下の通りです。
メールアドレス、もしくはパスワードを間違えた場合、フォームに入力した値が全てリセットされた状態で再びログイン画面がレンダリングされてしまいます。
これだとユーザーがパスワードの入力ミスをした場合、1からメールアドレスを打ち直さねばならないため、ユーザーにとって不便極まりありません。
そこで、今回はログインに失敗してもメールアドレスだけは保持するようにしていきます。
現状のコードは以下の通りです。
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
log_in(user)
flash[:notice] = "こんにちは、#{user.name}さん"
redirect_to user
else
flash.now[:error] = "ログインに失敗しました"
render "new", status: :unprocessable_entity
end
end
def destroy
log_out
redirect_to root_path, status: :see_other
end
end
<div class="row justify-content-center">
<%= form_with(scope: :session, url: login_path, local: true, class: "mt-4 form-column-width", html: {novalidate: false}) do |f| %>
<div class="mb-3">
<%= f.label :email, class: "form-label fw-bold"%>
<div class="input-group shadow-sm rounded">
<span class="input-group-text" id="basic-addon1">
<i class="bi bi-envelope"></i>
</span>
<%= f.email_field :email, class: "form-control", placeholder: "Eメールアドレスを入力してください" %>
</div>
</div>
<div class="mb-2">
<%= f.label :password, class: "form-label fw-bold"%>
<div class="input-group shadow-sm rounded">
<span class="input-group-text" id="basic-addon1">
<i class="bi bi-key-fill"></i>
</span>
<%= f.password_field :password, class: "form-control", placeholder: "パスワードを入力してください" %>
</div>
</div>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" value="" id="flexCheckDefault">
<label class="form-check-label" for="flexCheckDefault">
ログイン状態を保持する
</label>
</div>
<%= f.submit "ログイン", class: "btn btn-primary" %>
<% end %>
</div>
【解決策】ログイン失敗時にフォームに入力した値を保存する
ログイン失敗時にフォームに入力した値を保存するためには、userモデルのインスタンス変数を用いて、ログイン失敗時(newへレンダリング時)に値をフォームに受け渡す必要があります。
そこで、ログイン用のテンプレートapp/views/sessions/new.html.erb
のform_with
にmodel: @user
を追記します。
<div class="row justify-content-center">
<!----------------- ↓↓↓ model: @user を加える ↓↓↓ -------------------->
<%= form_with(scope: :session, model: @user, url: login_path, local: true, class: "mt-4 form-column-width", html: {novalidate: false}) do |f| %>
・・・
<% end %>
</div>
続いて、app/controllers/sessions_controller.rb
を以下のように書き換えます。
class SessionsController < ApplicationController
def new
end
def create
# user を @userに, params[:session][:email] を session_params[:email] に置き換える
# params[:session][:password] を session_params[:password]に置き換える
@user = User.find_by(email: session_params[:email].downcase)
if @user && @user.authenticate(session_params[:password])
log_in(@user)
flash[:notice] = "こんにちは、#{@user.name}さん"
redirect_to @user
else
#------------追記--------------
@user = User.new(session_params)
#-----------------------------
flash.now[:error] = "ログインに失敗しました"
render "new", status: :unprocessable_entity
end
end
def destroy
log_out
redirect_to root_path, status: :see_other
end
private
#------------追記--------------
def session_params
params.require(:session).permit(:email, :password)
end
#-----------------------------
end
上記のコードに書き換えることで、フォーム送信前にフォームで入力した値(メールアドレス)を受け取り、ログイン失敗時にレンダリング先new.html.erb
のフォームに値を渡します。
コード変更後の挙動は以下の通りです。
これで、ログイン失敗時に入力されたフォームの値(メールアドレス)が保持されるようになりました。
以上です。
コメント