首页 > 解决方案 > 验证错误:“密码不能为空”,但不能为空

问题描述

它一直说密码字段和密码确认字段为空白,即使我使用 rails 控制台创建新用户也是如此。此外,密码确认的错误消息重复出现,我不知道为什么。任何帮助将不胜感激。

错误消息的屏幕截图

用户模型

class User < ApplicationRecord
  has_secure_password
  validates_confirmation_of :password
  attr_accessor :password
  validates :password, length: 6..100, confirmation: true
  validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, on: :create }
  before_save :encrypt_password
  validates_presence_of :password_confirmation, if: lambda {| u| u.password.present? }


  def encrypt_password
    self.password_salt = BCrypt::Engine.generate_salt
    self.password_hash = BCrypt::Engine.hash_secret(password,password_salt)

  end
end

用户控制器

  class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def index
  end

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

  def create
    @user = User.new(user_params)
    if @user.save and user.valid?
      session[:user_id] = @user.id
      render 'users/new'
    else
      render :action => "new"
    end
  end

  private
  def user_params
    params.required(:user).permit(:name, :email, :password, :password_confirmation)
  end
end

用户/注册视图

<%= stylesheet_link_tag "signup.css" %>

<div id = signup_image></div>
<div id = signup-background>
  <div id = signup-text>
    <h1 style = "color: rgb(40,50,60);">Sign up</h1>
    <%= form_for :user,url: '/users' do |f| %>
      <br> <%= f.text_field :name, placeholder: "Name", class: 'signup-textfield'%><br>
      <br><%= f.text_field :email, placeholder:"email@gmail.com", class: 'signup-textfield' %><br>
      <br><%= f.password_field :password, placeholder: "Password",class: 'signup-textfield' %><br>
      <br><%= f.password_field :password_confirmation, placeholder: "Confirm password",class: 'signup-textfield' %><br>
      <br>
      <%= f.submit id: "signup-button"%>
    <% end %>
    <br>
    <small>Already have an account?  <%=link_to "Login here", "/login" %></small>
  </div>
</div>

用户新视图

<div id = signup_image></div>
<div id = signup-background>
  <div id = signup-text>
    <h1 style = "color: rgb(40,50,60);">Sign up</h1>
      <div class="row">
        <div class="span6 offset3">
            <%= render :partial => 'shared/error_message_form' %>
        </div>
      </div>
    <%= form_for @user do |f| %>
        <br> <%= f.text_field :name , placeholder: "Name", class: 'signup-textfield'%>
        <br><%= f.text_field :email,  placeholder:"email@gmail.com", class: 'signup-textfield' %>
        <br><%= f.password_field :password_digest, placeholder: "Password",class: 'signup-textfield' %>
        <br><%= f.password_field :password_confirmation, placeholder: "Confirm password",class: 'signup-textfield' %>
        <br>
        <%= f.submit id: "signup-button"%>
    <% end %>
    <br><br>

    <small>Already have an account?  <%=link_to "Login here", "/login" %></small>
  </div>
</div>

错误消息的部分

<% if @user.errors.any? %>
  <div id="error_explanation">
    <div class="alert alert-error">
      <%= pluralize(@user.errors.count, "error")%> detected while signing up.
    </div>
    <ul>
      <br>
      <% @user.errors.full_messages.each do |msg| %>
        <li>* <%= msg %></li>
      <% end %>
    </ul>
  </div>
<% end %>

en.yml 文件

en:
  hello: "Hello world"
  activerecord:
    models:
      user:
    attributes:
      user:
        email: "Email address"
    errors:
      models:
        user:
          attributes:
            email:
              blank: "cannot be empty"
              taken: "%{value} is already taken"

标签: ruby-on-rails

解决方案


这里有很多问题,如果您是新手,这很正常。

模型

这实际上就是您所需要的:

class User < ApplicationRecord
  has_secure_password
  validates :email, 
      format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i }
end
  • has_secure_password为您设置密码加密。您不需要手动加密密码。您也不需要设置任何验证,因为它已经为您设置了它们:

    • 创建时必须存在密码
    • 密码长度应小于或等于 72 字节
    • 密码确认(使用 XXX_confirmation 属性)
  • 如果你想提供你自己的验证逻辑,你应该使用它has_secure_password(validations: false)来避免重复验证。但首先要学会使用框架。

  • 仅使用attr_accessor :passwordclobbers 创建的 setter has_secure_password。它几乎不应该在模型中使用。

  • 仅在创建时验证电子邮件格式是没有意义的。

控制器

class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def index
  end

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

  def create
    @user = User.new(user_params)
    if @user.save
      session[:user_id] = @user.id
      redirect_to root_path, notice: 'Welcome! ...' 
    else
      render :new
    end
  end

  private
  def user_params
    # the method is called require not required
    params.require(:user)
          .permit(:name, :email, :password, :password_confirmation)
  end
end
  • .save.valid?在尝试保存记录之前调用。因此@user.save and user.valid?完全是多余的。您还应该始终检查返回值,.save而不是.valid?在极少数情况下验证可能会通过,但数据库可能仍会拒绝插入查询。
  • 使用&&而不是and关键字,因为后者具有不同的运算符优先级。
  • 您应该在注册后将用户重定向到有意义的地方,而不是render 'users/new'.
  • render 'users/new'和 renderrender :action => "new"都是render :new.

看法

不要重复表格。使用部分:

# app/views/users/_form.html.erb
<%= form_with(model: user) do |f| %>
  <div class="field">
    <%= f.label :name %>
    <%= f.text_field :name, class: 'signup-textfield'%>
  </div>
  <div class="field">
    <%= f.label :email %>
    <%= f.email_field :email, placeholder: "email@example.com", class: 'signup-textfield' %>
   </div>
   <div class="field">
     <%= f.label :password %>
     <%= f.password_field :password, class: 'signup-textfield' %>
   </div>
   <div class="field">
     <%= f.label :password_confirmation %>
     <%= f.password_field :password_confirmation, class: 'signup-textfield' %>
   </div>
   <div class="actions">
     <%= f.submit id: "signup-button" %>
   </div>
<% end %>
<div id = signup_image></div>
<div id = signup-background>
  <div id = signup-text>
    <h1 style = "color: rgb(40,50,60);">Sign up</h1>
      <div class="row">
        <div class="span6 offset3">
          <%= render partial: 'shared/error_message_form' %>
        </div>
      </div>
      <%= render partial: 'form', locals: { user: @user } %>
    <small>Already have an account?  <%=link_to "Login here", "/login" %></small>
  </div>
</div>
  • 您缺少密码输入!
  • 不要使用密码摘要的输入!它从明文输入在服务器上生成,并且永远不应该真正暴露给用户。
  • 停止使用<br>标签。使用内容标签(例如<div>)来包装输入和标签,以便可以使用 CSS 设置样式,不再是 2005 年了。<br>只能用于将文本分成几行。不适用于视觉间距。
  • 不要使用placeholder属性代替标签。它是一种对可用性和可访问性来说非常糟糕的反模式
  • 使用约定而不是配置,只需将模型实例传递给form_with/ form_for。Rails 可以自己找出路径。避免使用符号 - 调用表单form_for :user。执行的实例变量/方法查找不那么明确,并且被认为是 Rails 魔术的一个案例。这种行为没有延续到form_with.
  • 你真的需要一个单独的用户/注册视图来复制整个事情吗?

推荐阅读