nil的未定义方法`errors':传递User对象时的NilClass

时间:2022-12-05 16:06:41

My application has user accounts and the users can log in to view the application. When a user is created by an admin a random password is generated and the user is prompted to change this if this is their first time logging in. Here is my SessionsController:

我的应用程序有用户帐户,用户可以登录查看应用程序。当管理员创建用户时,会生成随机密码,如果这是他们第一次登录,则会提示用户更改此密码。这是我的SessionsController:

class SessionsController < ApplicationController

  def new
  end

  def create
    user = User.find_by(user_name: params[:session][:user_name].to_s.downcase)
    if user && user.authenticate(params[:session][:password])
      # Log the user in and redirect to the user's show page.
      if user.created_at == user.updated_at
        # If this is a first time user, then they need to change their password.
        log_in user



        # This user object is correct at this point, but after this point it is nil.
        redirect_to change_password_path(user)
      else
        log_in user
        redirect_to root_path # Redirects to the main page (parts page)
      end
    else
      # Create an error message.
      flash.now[:danger] = 'Invalid User Name/Password combination'
      render 'new'
    end
  end

  def destroy
    log_out
    redirect_to login_path
  end

end

Before being redirected to the change_password_path, the user object is not nil. Here are my routes for the redirect.

在重定向到change_password_path之前,用户对象不是nil。以下是重定向的路由。

Rails.application.routes.draw do

  get 'sessions/new'

  resources :parts
  resources :users
  root "parts#index"

  get    '/change_password', to: 'users#first_time_password_change'
  get    '/login',   to: 'sessions#new'
  post   '/login',   to: 'sessions#create'
  delete '/logout',  to: 'sessions#destroy'

end

Once the user is redirected to change their password, the user object is nil and throws an error at _change_password.html.erb. Here is the error and the stack trace:

重定向用户以更改其密码后,用户对象为nil并在_change_password.html.erb处引发错误。这是错误和堆栈跟踪:

undefined method `errors' for nil:NilClass

app/views/users/_change_password.html.erb:2:in `block in _app_views_users__change_password_html_erb__3382781422752759150_70150174196820'
actionview (5.1.4) lib/action_view/helpers/capture_helper.rb:39:in `block in capture'
actionview (5.1.4) lib/action_view/helpers/capture_helper.rb:203:in `with_output_buffer'
actionview (5.1.4) lib/action_view/helpers/capture_helper.rb:39:in `capture'
actionview (5.1.4) lib/action_view/helpers/form_helper.rb:758:in `form_with'
app/views/users/_change_password.html.erb:1:in `_app_views_users__change_password_html_erb__3382781422752759150_70150174196820'
actionview (5.1.4) lib/action_view/template.rb:157:in `block in render'
activesupport (5.1.4) lib/active_support/notifications.rb:168:in `instrument'
actionview (5.1.4) lib/action_view/template.rb:352:in `instrument_render_template'
actionview (5.1.4) lib/action_view/template.rb:155:in `render'
actionview (5.1.4) lib/action_view/renderer/partial_renderer.rb:342:in `block in render_partial'
actionview (5.1.4) lib/action_view/renderer/abstract_renderer.rb:42:in `block in instrument'
activesupport (5.1.4) lib/active_support/notifications.rb:166:in `block in instrument'
activesupport (5.1.4) lib/active_support/notifications/instrumenter.rb:21:in `instrument'
activesupport (5.1.4) lib/active_support/notifications.rb:166:in `instrument'
actionview (5.1.4) lib/action_view/renderer/abstract_renderer.rb:41:in `instrument'
actionview (5.1.4) lib/action_view/renderer/partial_renderer.rb:331:in `render_partial'
actionview (5.1.4) lib/action_view/renderer/partial_renderer.rb:310:in `render'
actionview (5.1.4) lib/action_view/renderer/renderer.rb:47:in `render_partial'
actionview (5.1.4) lib/action_view/helpers/rendering_helper.rb:35:in `render'
app/views/users/first_time_password_change.html.erb:1:in `_app_views_users_first_time_password_change_html_erb___4022541670546187761_70150174275000'
actionview (5.1.4) lib/action_view/template.rb:157:in `block in render'
activesupport (5.1.4) lib/active_support/notifications.rb:168:in `instrument'
actionview (5.1.4) lib/action_view/template.rb:352:in `instrument_render_template'
actionview (5.1.4) lib/action_view/template.rb:155:in `render'
actionview (5.1.4) lib/action_view/renderer/template_renderer.rb:52:in `block (2 levels) in render_template'
actionview (5.1.4) lib/action_view/renderer/abstract_renderer.rb:42:in `block in instrument'
activesupport (5.1.4) lib/active_support/notifications.rb:166:in `block in instrument'
activesupport (5.1.4) lib/active_support/notifications/instrumenter.rb:21:in `instrument'
activesupport (5.1.4) lib/active_support/notifications.rb:166:in `instrument'
actionview (5.1.4) lib/action_view/renderer/abstract_renderer.rb:41:in `instrument'
actionview (5.1.4) lib/action_view/renderer/template_renderer.rb:51:in `block in render_template'
actionview (5.1.4) lib/action_view/renderer/template_renderer.rb:59:in `render_with_layout'
actionview (5.1.4) lib/action_view/renderer/template_renderer.rb:50:in `render_template'
actionview (5.1.4) lib/action_view/renderer/template_renderer.rb:14:in `render'
actionview (5.1.4) lib/action_view/renderer/renderer.rb:42:in `render_template'
actionview (5.1.4) lib/action_view/renderer/renderer.rb:23:in `render'
actionview (5.1.4) lib/action_view/rendering.rb:103:in `_render_template'
actionpack (5.1.4) lib/action_controller/metal/streaming.rb:217:in `_render_template'
actionview (5.1.4) lib/action_view/rendering.rb:83:in `render_to_body'
actionpack (5.1.4) lib/action_controller/metal/rendering.rb:52:in `render_to_body'
actionpack (5.1.4) lib/action_controller/metal/renderers.rb:141:in `render_to_body'
actionpack (5.1.4) lib/abstract_controller/rendering.rb:24:in `render'
actionpack (5.1.4) lib/action_controller/metal/rendering.rb:36:in `render'
actionpack (5.1.4) lib/action_controller/metal/instrumentation.rb:44:in `block (2 levels) in render'
activesupport (5.1.4) lib/active_support/core_ext/benchmark.rb:12:in `block in ms'
/usr/local/rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/benchmark.rb:308:in `realtime'
activesupport (5.1.4) lib/active_support/core_ext/benchmark.rb:12:in `ms'
actionpack (5.1.4) lib/action_controller/metal/instrumentation.rb:44:in `block in render'
actionpack (5.1.4) lib/action_controller/metal/instrumentation.rb:87:in `cleanup_view_runtime'
activerecord (5.1.4) lib/active_record/railties/controller_runtime.rb:29:in `cleanup_view_runtime'
actionpack (5.1.4) lib/action_controller/metal/instrumentation.rb:43:in `render'
actionpack (5.1.4) lib/action_controller/metal/implicit_render.rb:33:in `default_render'
actionpack (5.1.4) lib/action_controller/metal/basic_implicit_render.rb:4:in `block in send_action'
actionpack (5.1.4) lib/action_controller/metal/basic_implicit_render.rb:4:in `tap'
actionpack (5.1.4) lib/action_controller/metal/basic_implicit_render.rb:4:in `send_action'
actionpack (5.1.4) lib/abstract_controller/base.rb:186:in `process_action'
actionpack (5.1.4) lib/action_controller/metal/rendering.rb:30:in `process_action'
actionpack (5.1.4) lib/abstract_controller/callbacks.rb:20:in `block in process_action'
activesupport (5.1.4) lib/active_support/callbacks.rb:131:in `run_callbacks'
actionpack (5.1.4) lib/abstract_controller/callbacks.rb:19:in `process_action'
actionpack (5.1.4) lib/action_controller/metal/rescue.rb:20:in `process_action'
actionpack (5.1.4) lib/action_controller/metal/instrumentation.rb:32:in `block in process_action'
activesupport (5.1.4) lib/active_support/notifications.rb:166:in `block in instrument'
activesupport (5.1.4) lib/active_support/notifications/instrumenter.rb:21:in `instrument'
activesupport (5.1.4) lib/active_support/notifications.rb:166:in `instrument'
actionpack (5.1.4) lib/action_controller/metal/instrumentation.rb:30:in `process_action'
actionpack (5.1.4) lib/action_controller/metal/params_wrapper.rb:252:in `process_action'
activerecord (5.1.4) lib/active_record/railties/controller_runtime.rb:22:in `process_action'
actionpack (5.1.4) lib/abstract_controller/base.rb:124:in `process'
actionview (5.1.4) lib/action_view/rendering.rb:30:in `process'
actionpack (5.1.4) lib/action_controller/metal.rb:189:in `dispatch'
actionpack (5.1.4) lib/action_controller/metal.rb:253:in `dispatch'
actionpack (5.1.4) lib/action_dispatch/routing/route_set.rb:49:in `dispatch'
actionpack (5.1.4) lib/action_dispatch/routing/route_set.rb:31:in `serve'
actionpack (5.1.4) lib/action_dispatch/journey/router.rb:50:in `block in serve'
actionpack (5.1.4) lib/action_dispatch/journey/router.rb:33:in `each'
actionpack (5.1.4) lib/action_dispatch/journey/router.rb:33:in `serve'
actionpack (5.1.4) lib/action_dispatch/routing/route_set.rb:834:in `call'
rack (2.0.3) lib/rack/etag.rb:25:in `call'
rack (2.0.3) lib/rack/conditional_get.rb:25:in `call'
rack (2.0.3) lib/rack/head.rb:12:in `call'
rack (2.0.3) lib/rack/session/abstract/id.rb:232:in `context'
rack (2.0.3) lib/rack/session/abstract/id.rb:226:in `call'
actionpack (5.1.4) lib/action_dispatch/middleware/cookies.rb:613:in `call'
activerecord (5.1.4) lib/active_record/migration.rb:556:in `call'
actionpack (5.1.4) lib/action_dispatch/middleware/callbacks.rb:26:in `block in call'
activesupport (5.1.4) lib/active_support/callbacks.rb:97:in `run_callbacks'
actionpack (5.1.4) lib/action_dispatch/middleware/callbacks.rb:24:in `call'
actionpack (5.1.4) lib/action_dispatch/middleware/executor.rb:12:in `call'
actionpack (5.1.4) lib/action_dispatch/middleware/debug_exceptions.rb:59:in `call'
web-console (3.5.1) lib/web_console/middleware.rb:135:in `call_app'
web-console (3.5.1) lib/web_console/middleware.rb:20:in `block in call'
web-console (3.5.1) lib/web_console/middleware.rb:18:in `catch'
web-console (3.5.1) lib/web_console/middleware.rb:18:in `call'
actionpack (5.1.4) lib/action_dispatch/middleware/show_exceptions.rb:31:in `call'
railties (5.1.4) lib/rails/rack/logger.rb:36:in `call_app'
railties (5.1.4) lib/rails/rack/logger.rb:24:in `block in call'
activesupport (5.1.4) lib/active_support/tagged_logging.rb:69:in `block in tagged'
activesupport (5.1.4) lib/active_support/tagged_logging.rb:26:in `tagged'
activesupport (5.1.4) lib/active_support/tagged_logging.rb:69:in `tagged'
railties (5.1.4) lib/rails/rack/logger.rb:24:in `call'
sprockets-rails (3.2.1) lib/sprockets/rails/quiet_assets.rb:13:in `call'
actionpack (5.1.4) lib/action_dispatch/middleware/remote_ip.rb:79:in `call'
request_store (1.4.0) lib/request_store/middleware.rb:19:in `call'
actionpack (5.1.4) lib/action_dispatch/middleware/request_id.rb:25:in `call'
rack (2.0.3) lib/rack/method_override.rb:22:in `call'
rack (2.0.3) lib/rack/runtime.rb:22:in `call'
activesupport (5.1.4) lib/active_support/cache/strategy/local_cache_middleware.rb:27:in `call'
actionpack (5.1.4) lib/action_dispatch/middleware/executor.rb:12:in `call'
actionpack (5.1.4) lib/action_dispatch/middleware/static.rb:125:in `call'
rack (2.0.3) lib/rack/sendfile.rb:111:in `call'
railties (5.1.4) lib/rails/engine.rb:522:in `call'
puma (3.11.0) lib/puma/configuration.rb:225:in `call'
puma (3.11.0) lib/puma/server.rb:624:in `handle_request'
puma (3.11.0) lib/puma/server.rb:438:in `process_client'
puma (3.11.0) lib/puma/server.rb:302:in `block in run'
puma (3.11.0) lib/puma/thread_pool.rb:120:in `block in spawn_thread'

Here are the first_time_password_change.html.erb

这是first_time_password_change.html.erb

<%= render 'change_password', user: @user %>
<%= logger.info "FUDGE " + @user.class.to_s %>
<div class="row">
    <div class="col-md-6 col-md-offset-3">
        <%= link_to 'Show', @user %> |
        <%= link_to 'Back', users_path %>
    </div>
</div>

Here is the _change_password.html.erb

这是_change_password.html.erb

<%= form_with(model: user, local: true) do |form| %>
  <% if user.errors.any? %>
    <div id="error_explanation">
      <h2 style="color: red;"><%= pluralize(user.errors.count, "error") %> prohibited this user from being saved:</h2>
      <ul>
      <% user.errors.full_messages.each do |message| %>
        <li style="color: red;"><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <h1>Change Password</h1>
    <div class="control-group">
      <%= form.label :first_name, class: "control-label" %>
      <label style="font-size: 20px; font-weight:normal;">&nbsp;&nbsp;&nbsp;<%= @user.first_name %></label>
    </div><br />

    <div class="control-group">
      <%= form.label :last_name, class: "control-label" %>
      <label style="font-size: 20px; font-weight:normal;">&nbsp;&nbsp;&nbsp;<%= @user.last_name %></label>
    </div><br />

    <div class="control-group">
      <%= form.label :user_name, class: "control-label" %>
      <label style="font-size: 20px; font-weight:normal;">&nbsp;&nbsp;<%= @user.user_name %></label>
    </div><br />

    <div class="control-group">
      <%= form.label :email, class: "control-label" %>
      <label style="font-size: 20px; font-weight:normal;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<%= @user.email %></label>
    </div><br />

    <div class="control-group">
      <%= form.label :privledges, class: "control-label"%>
      <label style="font-size: 20px; font-weight:normal;">&nbsp;&nbsp;<%= @user.privledges %></label>
    </div><br />

    <div class="control-group">
      <%= form.label :new_password, class: "control-label" %>
      <%= form.text_field :password, id: :password, class: 'form-control', value: "" %>
    </div><br />

    <div class="control-group">
      <%= form.label :confirm_password, class: "control-label" %>
      <%= form.text_field :confirm_password, id: :confirm_password, class: 'form-control' %>
    </div><br />

    <div class="actions">
      <%= form.submit 'Change Password', class: "btn btn-primary" %>
    </div>
    <br />

  </div>
</div>
<% end %>

And Here is the UserController

这是UserController

require 'rubygems'
require 'random_password_generator'

class UsersController < ApplicationController
  # Check that the person accessing the application is logged in:
  before_action :authenticate_user!
  before_action :set_user, only: [:show, :edit, :update, :destroy]

  # GET /users
  # GET /users.json
  def index
    @users = User.all
  end

  # GET /users/1
  # GET /users/1.json
  def show
  end

  # GET /users/new
  def new
    @user = User.new
  end

  # GET /users/1/edit
  def edit
  end

  # GET /changepassword
  def first_time_password_change
  end

  # POST /users
  # POST /users.json
  def create
    @user = User.new(user_params)
    @user.password = RandomPasswordGenerator.generate(10, :skip_symbols => true).to_s
    respond_to do |format|
      if @user.save 
        format.html { redirect_to @user, notice: 'User was successfully created.' }
        format.json { render :show, status: :created, location: @user }
      else
        format.html { render :new }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /users/1
  # PATCH/PUT /users/1.json
  def update
    password_is_valid = password_update_is_valid(@user)
    respond_to do |format|
      if password_is_valid
        if @user.update(user_params)
          format.html { redirect_to @user, notice: 'User was successfully updated.' }
          format.json { render :show, status: :ok, location: @user }
        else
          format.html { render :edit }
          format.json { render json: @user.errors, status: :unprocessable_entity }
        end 
      else
        format.html { render :edit, notice: '' }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /users/1
  # DELETE /users/1.json
  def destroy
    @user.destroy
    respond_to do |format|
      format.html { redirect_to users_url, notice: 'User was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private 
  def password_update_is_valid(user)
    is_valid = true
    user_pass = params[:user][:password]
    user_conf = params[:user][:confirm_password]
    # Check if the parameters were passed as nil objects
    if user_pass.nil? or user_conf.nil?
      is_valid = false
      user.errors[:base] << "Please fill both the Password and Confirm Password fields."
    else
      # Check if the password and confirmation passwords are empty
      if user_pass == "" or user_conf == ""
        user.errors[:base] << "Please fill both the Password and Confirm Password fields."
        is_valid = false
      end
      # Check if the password length is less than 5 characters long
      if user_pass.length < 5
        user.errors[:base] << "Password must be at least 5 characters long."
        is_valid = false
      end
      # Check if the password and confirm password fields match.
      if user_pass != user_conf
        user.errors[:base] << "Password and Confirm Password must match."
        is_valid = false
      end
    end
    return is_valid
  end

  private
    def set_user
      @user = User.find(params[:id])
    end

    def user_params
      params.require(:user).permit(:first_name, :last_name, :user_name, :email, :password, :privledges, :password_digest)
    end

end

I am a bit new to rails but the console has some strange output. The first_time_change_password.html.erb is being rendered, followed by the _change_password.html.erb, which is as expected. What is weird is that the first_time_change_password.html.erb is rendered again and the error occurs.

我对rails有点新,但控制台有一些奇怪的输出。正在呈现first_time_change_password.html.erb,然后是_change_password.html.erb,这是预期的。奇怪的是,first_time_change_password.html.erb再次呈现并发生错误。

tarted GET "/change_password.21" for 107.213.96.34 at 2018-01-11 15:48:10 +0000
Cannot render console from 107.213.96.34! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by UsersController#first_time_password_change as 
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 21], ["LIMIT", 1]]
  Rendering users/first_time_password_change.html.erb within layouts/application
  Rendered users/_change_password.html.erb (4.6ms)
  Rendered users/first_time_password_change.html.erb within layouts/application (8.1ms)
Completed 500 Internal Server Error in 17ms (ActiveRecord: 0.1ms)



ActionView::Template::Error (undefined method `errors' for nil:NilClass):
    1: <%= form_with(model: user, local: true) do |form| %>
    2:   <% if user.errors.any? %>
    3:     <div id="error_explanation">
    4:       <h2 style="color: red;"><%= pluralize(user.errors.count, "error") %> prohibited this user from being saved:</h2>
    5:       <ul>

app/views/users/_change_password.html.erb:2:in `block in _app_views_users__change_password_html_erb__3382781422752759150_70150174196820'
app/views/users/_change_password.html.erb:1:in `_app_views_users__change_password_html_erb__3382781422752759150_70150174196820'
app/views/users/first_time_password_change.html.erb:1:in `_app_views_users_first_time_password_change_html_erb___4022541670546187761_70150174275000'

I am a bit new to rails and I am studying web development so please have mercy on me.

我对rails有点新,我正在研究Web开发,所以请怜悯我吧。

Also, I am running Rails 5.1.4 on Cloud 9.

另外,我在Cloud 9上运行Rails 5.1.4。

Thank you to everyone who is willing to take the time to look at this and I am sorry about all of the code.

感谢所有愿意花时间看这个的人,我对所有的代码感到抱歉。

3 个解决方案

#1


0  

In the UsersController in the before action before_action :set_user, only: [:show, :edit, :update, :destroy] add the first_time_password_change method. before_action :set_user, only: [:show, :edit, :update, :destroy, :first_time_password_change] As @user is not set in that method user is nil.

在before action的before_action:set_user中的UsersController中,只有:[:show,:edit,:update,:destroy]添加first_time_password_change方法。 before_action:set_user,only:[:show,:edit,:update,:destroy,:first_time_password_change]由于@user未在该方法中设置,因此用户为nil。

#2


0  


Since you asked for an explanation, you were seeing undefined method 'errors' for nil:NilClass because user object is actually nil there. All starts when you call <%= render 'change_password', user: @user %> without setting @user in your action first_time_password_change. Devise makes a helper current_user available if a user is logged in. Since you make the action available only to authenticated users with before_action :authenticate_user!, it's recommended to use current_user rather than setting up another instance @user. And you can make use of current_user in the partial directly without passing it in locals. Hope this will help.

因为你要求解释,你看到nil的未定义方法'errors':NilClass因为用户对象实际上是nil。当您调用<%= render'change_password',user:@user%>而不在您的操作first_time_password_change中设置@user时,全部启动。如果用户已登录,Devise会使帮助程序current_user可用。由于您只对经过身份验证的用户使用before_action:authenticate_user!,因此建议使用current_user而不是设置另一个实例@user。并且您可以直接在部分中使用current_user,而无需在本地传递它。希望这会有所帮助。

#3


0  

First of all, this is not a server-side validation this called client-side validation, this matching user data not creating data with validation

首先,这不是服务器端验证,这称为客户端验证,这种匹配的用户数据不会通过验证创建数据

Login

Allow a user to sign in with her/his valid email/username and password. The authentication process happens by matching the email/username and password in the database, allowing the user access to the protected actions only if the given information matches the recorded values successfully. If not, the user will be redirected to the login page again.

允许用户使用她/他的有效电子邮件/用户名和密码登录。通过匹配数据库中的电子邮件/用户名和密码来进行身份验证过程,仅当给定信息与记录值成功匹配时,才允许用户访问受保护的操作。如果没有,用户将再次被重定向到登录页面。

This is not creating data to the database with model validation this is matching data with a database which already exist after that create a session to hold id.

这不是通过模型验证向数据库创建数据,这是与数据库匹配的数据,该数据库在创建会话以保存id之后已经存在。

That's why you need to remove this client-side error code only for login form, after removing this code

这就是为什么在删除此代码后,您只需要为登录表单删除此客户端错误代码

<% if user.errors.any? %>
    <div id="error_explanation">
      <h2 style="color: red;"><%= pluralize(user.errors.count, "error") %> prohibited this user from being saved:</h2>
        <ul>
            <% user.errors.full_messages.each do |message| %>
                <li style="color: red;"><%= message %></li>
            <% end %>
        </ul>
    </div>
<% end %>

Add flash section which holds your login error like below

添加flash部分,保存您的登录错误,如下所示

<% flash.each do |name, msg| %>
    <section class="<%="#{name}" %>-message-section"> 
        <div class="container"> 
            <div class="row"> 
                <div class="col-md-12"> 
                    <div class="alert-message <%="#{name}" %>-message">
                        <p><%= msg if msg.is_a?(String) %></p>
                        <i class="icofont icofont-close"></i>
                    </div>
                </div>
            </div>
        </div>
    </section>
<% end %>

Hope to help

希望能有所帮助

#1


0  

In the UsersController in the before action before_action :set_user, only: [:show, :edit, :update, :destroy] add the first_time_password_change method. before_action :set_user, only: [:show, :edit, :update, :destroy, :first_time_password_change] As @user is not set in that method user is nil.

在before action的before_action:set_user中的UsersController中,只有:[:show,:edit,:update,:destroy]添加first_time_password_change方法。 before_action:set_user,only:[:show,:edit,:update,:destroy,:first_time_password_change]由于@user未在该方法中设置,因此用户为nil。

#2


0  


Since you asked for an explanation, you were seeing undefined method 'errors' for nil:NilClass because user object is actually nil there. All starts when you call <%= render 'change_password', user: @user %> without setting @user in your action first_time_password_change. Devise makes a helper current_user available if a user is logged in. Since you make the action available only to authenticated users with before_action :authenticate_user!, it's recommended to use current_user rather than setting up another instance @user. And you can make use of current_user in the partial directly without passing it in locals. Hope this will help.

因为你要求解释,你看到nil的未定义方法'errors':NilClass因为用户对象实际上是nil。当您调用<%= render'change_password',user:@user%>而不在您的操作first_time_password_change中设置@user时,全部启动。如果用户已登录,Devise会使帮助程序current_user可用。由于您只对经过身份验证的用户使用before_action:authenticate_user!,因此建议使用current_user而不是设置另一个实例@user。并且您可以直接在部分中使用current_user,而无需在本地传递它。希望这会有所帮助。

#3


0  

First of all, this is not a server-side validation this called client-side validation, this matching user data not creating data with validation

首先,这不是服务器端验证,这称为客户端验证,这种匹配的用户数据不会通过验证创建数据

Login

Allow a user to sign in with her/his valid email/username and password. The authentication process happens by matching the email/username and password in the database, allowing the user access to the protected actions only if the given information matches the recorded values successfully. If not, the user will be redirected to the login page again.

允许用户使用她/他的有效电子邮件/用户名和密码登录。通过匹配数据库中的电子邮件/用户名和密码来进行身份验证过程,仅当给定信息与记录值成功匹配时,才允许用户访问受保护的操作。如果没有,用户将再次被重定向到登录页面。

This is not creating data to the database with model validation this is matching data with a database which already exist after that create a session to hold id.

这不是通过模型验证向数据库创建数据,这是与数据库匹配的数据,该数据库在创建会话以保存id之后已经存在。

That's why you need to remove this client-side error code only for login form, after removing this code

这就是为什么在删除此代码后,您只需要为登录表单删除此客户端错误代码

<% if user.errors.any? %>
    <div id="error_explanation">
      <h2 style="color: red;"><%= pluralize(user.errors.count, "error") %> prohibited this user from being saved:</h2>
        <ul>
            <% user.errors.full_messages.each do |message| %>
                <li style="color: red;"><%= message %></li>
            <% end %>
        </ul>
    </div>
<% end %>

Add flash section which holds your login error like below

添加flash部分,保存您的登录错误,如下所示

<% flash.each do |name, msg| %>
    <section class="<%="#{name}" %>-message-section"> 
        <div class="container"> 
            <div class="row"> 
                <div class="col-md-12"> 
                    <div class="alert-message <%="#{name}" %>-message">
                        <p><%= msg if msg.is_a?(String) %></p>
                        <i class="icofont icofont-close"></i>
                    </div>
                </div>
            </div>
        </div>
    </section>
<% end %>

Hope to help

希望能有所帮助