【Rails】ログイン失敗時にフォームに入力した値を保持する

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.erbform_withmodel: @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のフォームに値を渡します。

コード変更後の挙動は以下の通りです。

これで、ログイン失敗時に入力されたフォームの値(メールアドレス)が保持されるようになりました。

以上です。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

愛知の34歳。無職で暇になり始めたプログラミング(Ruby on Rails)の忘備録をまとめたブログです。最近は別にやりたいことができたのでプログラミングほぼやっていません。気が向いたらまた再開するかも。僕の日常はメインブログの方で更新しています。

コメント

コメントする

目次