CarbazochromeT / drug_app

drug_app
0 stars 0 forks source link

フォーム入力時のバリデーションによるエラーメッセージを表示させたい #7

Closed CarbazochromeT closed 11 months ago

CarbazochromeT commented 1 year ago

質問内容・実現したいこと

現在、Rails 7とSorceryを使用してログイン機能を実装しようとしています。 ログインページにて、Rails基礎編で出てきた課題10のフォーム入力の個別エラーを表示させたいのですが、objectの中身がnilになってしまいエラーが発生してしまいます。 詰まってしまっているので、アドバイス等いただけますと幸いです。

現状発生している問題・エラーメッセージ

09:02:11 web.1  | Processing by UserSessionsController#new as HTML
09:02:11 web.1  |   Rendering layout layouts/application.html.erb
09:02:11 web.1  |   Rendering user_sessions/new.html.erb within layouts/application
09:02:11 web.1  |   Rendered shared/_error_messages.html.erb (Duration: 8.1ms | Allocations: 2779)
09:02:11 web.1  |   Rendered user_sessions/new.html.erb within layouts/application (Duration: 15.8ms | Allocations: 5083)
09:02:11 web.1  |   Rendered layout layouts/application.html.erb (Duration: 17.5ms | Allocations: 5430)
09:02:11 web.1  | Completed 500  in 221ms (ActiveRecord: 0.0ms | Allocations: 90021)
09:02:11 web.1  | 
09:02:11 web.1  | 
09:02:11 web.1  |   
09:02:11 web.1  | ActionView::Template::Error (undefined method `errors' for nil:NilClass):
09:02:11 web.1  |     1: <% if object.errors.any? %>
09:02:11 web.1  |     2: <div id="error_messages", class="flash flash-danger" >
09:02:11 web.1  |     3:   <ul class="error-message">
09:02:11 web.1  |     4:     <% user.errors.full_messages.each do |message| %>
09:02:11 web.1  |   
09:02:11 web.1  | app/views/shared/_error_messages.html.erb:1
09:02:11 web.1  | app/views/user_sessions/new.html.erb:17
09:02:11 web.1  | app/views/user_sessions/new.html.erb:16

該当のソースコード

#user_sessions/new.html.erb
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="turbo-visit-control" content="reload">
  </head>
  <body>
<% content_for(:title, t('.title')) %>
<div class="top-header"></div>
<div class="container">

<hgroup>
  <h1><%= t '.title' %></h1><br>
  <h3>アカウント作成は<%= link_to 'こちら', new_user_path %></h3>
</hgroup>
  <%= form_with model:@user, url: login_path, local: true do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
    <div class="group">
      <%= f.label :email, User.human_attribute_name(:email) %><br>
      <%= f.text_field :email %><span class="highlight"></span><span class="bar"></span>
    </div>
    <div class="group">
      <%= f.label :password, User.human_attribute_name(:password) %><br>
      <%= f.password_field :password %><span class="highlight"></span><span class="bar"></span>
    </div>
      <%= f.submit (t 'defaults.login'), class: 'btnpink' %>
  <% end %>
</div>
</body>
#user_sessions_controller.rb
class UserSessionsController < ApplicationController
  skip_before_action :require_login, only: %i[new create]

  def new
  end

  def create
    @user = login(params[:email], params[:password])
    if @user
      redirect_back_or_to root_path, success: t('.success')
    else
      flash.now[:danger] = t('.fail')
      render :new
    end
  end

  def destroy
    logout
    redirect_to root_path, status: :see_other, success: t('.success')
  end
end
#users/new.html.erb

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="turbo-visit-control" content="reload">
  </head>
  <body>

<% content_for(:title, t('.title')) %>
<div class="top-header"></div>
<div class="container">
<hgroup>
  <h1><%= t '.title' %></h1><br>
  <h3>サインインは<%= link_to 'こちら', login_path %></h3>
</hgroup>
<%= form_with model: @user, local: true do |f| %>
<%= render 'shared/error_messages', object: f.object %>
  <div class="group" >
    <%= f.label :username %>
    <%= f.text_field :username %><span class="highlight"></span><span class="bar"></span>
  </div>

  <div class="group" >
    <%= f.label :email %>
    <%= f.text_field :email %><span class="highlight"></span><span class="bar"></span>
  </div>

  <div class="group" >
    <%= f.label :password %>
    <%= f.password_field :password %><span class="highlight"></span><span class="bar"></span>
  </div>

  <div class="group" >
    <%= f.label :password_confirmation %>
    <%= f.password_field :password_confirmation %><span class="highlight"></span><span class="bar"></span>
  </div>
    <%= f.submit nil, class: 'btnpink' %>
<% end %>
</div>

</body>
<% if object.errors.any? %>
<div id="error_messages", class="flash flash-danger" >
  <ul class="error-message">
    <% user.errors.full_messages.each do |message| %>
      <li><%= message %></li>
    <% end %>
  </ul>
</div>
<% end %>

エラーから考えられる原因

user_session/new.html.erbのページを開いた時点、つまりフォームに@userの情報を入力する前からエラーになってしまいます。 別の箇所に記述を変えた方がいいのでしょうか。

試したこと

objectの記述を@object、@userに変更してみましたが、やはりobjectの中身はnilになってしまいます。

>> object
=> nil
>> @user
=> nil
>> @user.errors
NoMethodError: undefined method `errors' for nil:NilClass
    from /Users/flare_home/workspace/runteq/応用編/drug_app5/app/views/shared/_error_messages.html.erb:1:in `_app_views_shared__error_messages_html_erb__2512611904796920409_27680'
>>  

参考にしたURL

https://school.runteq.jp/v2/questions/2738 https://teratail.com/questions/278602

kenchasonakai commented 1 year ago

Processing by UserSessionsController#new as HTML とあることからUserSessionsControllerのnewアクションが動いていることがわかります

user_sessions_contoroller.rbのnewアクションはは以下のようになっています

class UserSessionsController < ApplicationController
  skip_before_action :require_login, only: %i[new create]

  def new
  end
end

error表示用のパーシャルにobjectを渡している箇所は <%= render 'shared/error_messages', object: f.object %> と書いてあるのでform_withにmodelオプションで渡しているインスタンスがobjectに渡されることになります

modelオプションで渡している@userはnewアクションで定義されているか確認してみてください

また、ログイン時にUserモデルのバリデーションエラーを表示させる必要があるかどうかも考えてみてください

CarbazochromeT commented 1 year ago
<% if object.errors.any? %>
<div id="error_messages", class="flash flash-danger" >
  <ul class="error-message">
    <% user.errors.full_messages.each do |message| %>
      <li><%= message %></li>
    <% end %>
  </ul>
</div>
<% end %>

<% object.errors.full_messages.each do |message| %>に訂正したらmethodエラーメッセージはなくなりました。ありがとうございます。 言われてみればログインページにバリデーションエラーが表示されなくてもいいことに気がつきましたので削除いたしました。

今現在は、新規登録ページのバリデーションエラーと、ログイン失敗時の「ログインに失敗しました」の文字が出てこない状態です。

kenchasonakai commented 1 year ago

今現在は、新規登録ページのバリデーションエラーと、ログイン失敗時の「ログインに失敗しました」の文字が出てこない状態です。

こちらご自身でなにか調べたものがありましたら共有していただきたいです

CarbazochromeT commented 1 year ago

記述しそびれておりました、申し訳ございません。 コントローラー内の記述を下記のように訂正したところ、エラーメッセージが表示されるようになりました。

  def create
    @user = User.new(user_params)
    if @user.save
      redirect_to login_path, flash:{ success: t('.success' )}
    else
      flash.now[:danger] = t('.fail')
      render :new, status: :unprocessable_entity
    end
  end

どうやらRails7でバリデーションエラーを表示するにはstatus: :unprocessable_entityという記述を行う必要があるみたいです。 ありがとうございました。