为什么我在用户更新期间在没有更新密码时使用“密码不能为空”(Rails 4带有'has_secure_password')?

时间:2015-01-16 18:41:30

标签: validation ruby-on-rails-4

在我的Rails 4.0.9应用程序中,使用BCrypt 3.1.7和Clearance 1.4.2进行身份验证,我在更新用户信息时收到错误。尽管没有输入新密码或密码确认,我收到错误“密码不能为空。”

我在搜索引擎优化和谷歌搜索方面看起来很高,而且找不到任何解决方案。大部分都是针对早期版本的Rails,现在可能已经过时了,而其他版本并不适合我的确切情况(可能是因为我只是做了一些愚蠢的事情)。

我可以从编辑表单中删除密码和password_confirmation字段,但我希望用户能够更新他们的密码,同时还要更新他们的姓名或电子邮件地址,如果他们有这么倾向的话。

'has_secure_password'应该只在create上验证,但似乎也在更新时验证。为了解决这个问题,我已经禁用了我的用户模型对password和password_confirmation的验证,只需要使用'has_secure_password'来验证这些参数。你能明白为什么我收到验证错误吗?清除宝石是否会覆盖has_secure_passwords的默认行为,或以任何方式影响验证?

用户模型

class User < ActiveRecord::Base
include Clearance::User
belongs_to :studio
has_one :public_user

before_save { self.email = email.downcase }
before_create :create_remember_token
after_create :make_public_user

validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i
validates :email, presence: true,
                format:     { with: VALID_EMAIL_REGEX },
                uniqueness: { case_sensitive: false }
has_secure_password
#   validates :password, length: { minimum: 6, on: :create }
#   validates :password_confirmation, presence: { on: :create }
...

用户控制器

...
def edit
end

def update
  if @user.update_attributes(user_params)
    flash[:success] = "Profile updated"
    redirect_to @user
  else
    render 'edit'
  end
end

private


def user_params
  params.require(:user).permit(:name, :email, :password, :password_confirmation, :password_digest)
end
...

编辑表单(实际上是“_fields.html.erb”部分)

<%= render 'shared/error_messages', object: f.object %>

<div class="control-group">
        <%= f.label :name, class: "control-label" %>
<div class="controls">
        <%= f.text_field :name %>
    </div>
</div>

<div class="control-group">
    <%= f.label :email, class: "control-label" %>
<div class="controls">
        <%= f.text_field :email %>
    </div>
</div>

<div class="control-group">
    <%= f.label :password, class: "control-label" %>
<div class="controls">
        <%= f.password_field :password, placeholder: 'Enter new password if changing' %>
    </div>
</div>

<div class="control-group">
    <%= f.label :password_confirmation, "Confirmation", class: "control-label" %>
    <div class="controls">
        <%= f.password_field :password_confirmation, placeholder: 'Confirm your new password if changing' %>
    </div>
</div>

传递给控制器​​的参数

Parameters: {"utf8"=>"✓", "authenticity_token"=>"[FILTERED]", "user"=>{"name"=>"Ransom Kshlerin III", "email"=>"example-1@samplestudio.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Save changes", "id"=>"4"}

修改

当我禁用'has_secure_password'时,我仍然会收到验证错误,这让我相信Clearance的验证会返回错误。我想我需要覆盖Clearance的密码验证,但仅限于更新用户时。我应该怎么做呢?

编辑2:

我将采取完全不同的方法。我不会直接在此表单上重置密码,而是提供重置密码的链接,该链接会向用户发送一封电子邮件,其中包含重置密码的链接。

3 个答案:

答案 0 :(得分:2)

传递给控制器​​的参数中有"password"=>"", "password_confirmation"=>""出现(不要担心[FILTERED],这只意味着Rails不会将参数打印到日志)。

致电params.require(:user).permit(:password, :password_confirmation)包括{ password: "", password_confirmation: "", # plus the other keys }时。

将此哈希传递给@user.update_attributes({password: '', password_confirmation: ''})时,密码的状态验证将启动,并防止设置空密码。

不尝试设置空密码的一个选项可能是从user_params哈希中删除密钥,除非它们的值被认为存在。

def user_params
  user_params = params.require(:user).permit(:name, :email, :password, :password_confirmation) # don't permit `password_digest` here, that database column should not be allowed to be set by the user!

  # Remove the password and password confirmation keys for empty values
  user_params.delete(:password) unless user_params[:password].present?
  user_params.delete(:password_confirmation) unless user_params[:password_confirmation].present?

  user_params
end

答案 1 :(得分:0)

has_secure_password和Clearance gem每个都验证密码和密码确认,而且我还不够熟练,无法超越Clearance的验证(在我脑海中)。所以我采取了不同的方法。密码和密码确认不会包含在此编辑表单中。

我不会直接在此表单上重置密码,而是提供重置密码的链接,该链接会向用户发送一封电子邮件,其中包含重置密码的链接。我想这里的额外好处是,如果用户设法以其他用户身份登录,他们将无法重置该用户的密码,除非他们还侵入了其他用户&# 39;电子邮件帐户。

答案 2 :(得分:-1)

Clearance提供了一条明确的(^_^)路径来规避密码要求:

# Always false. Override this method in your user model to allow for other
# forms of user authentication (username, Facebook, etc).
#
# @return [false]
def password_optional?
  false
end

例如,在您的用户模型中,您可以执行以下操作:

# app/models/user.rb

class User < ApplicationRecord
  include Clearance::User

  def password_optional?
    true
  end
end

Source