Rails 4 - 仅在当前密码正确时才允许更改密码

Ale*_*der 5 authentication passwords model ruby-on-rails bcrypt-ruby

在我的应用中,用户可以编辑他们的个人资料信息 在编辑配置文件表单上,用户可以更改所有字段(名称,标题等).在此同一形式的三个字段:current_password,password,和password_confirmation.我使用bcrypthas_secure_password功能进行密码验证.我根本不使用Devise.

我希望用户只有在提供了正确的当前密码后才能更改密码.我之前在使用updateUsers控制器的方法中使用了以下代码:

# Check if the user tried changing his/her password and CANNOT be authenticated with the entered current password
if !the_params[:password].blank? && !@user.authenticate(the_params[:current_password])
  # Add an error that states the user's current password is incorrect
  @user.errors.add(:base, "Current password is incorrect.")
else    
  # Try to update the user
  if @user.update_attributes(the_params)
    # Notify the user that his/her profile was updated
    flash.now[:success] = "Your changes have been saved"
  end
end
Run Code Online (Sandbox Code Playgroud)

但是,此方法的问题在于,如果仅当前密码不正确,则会丢弃对用户模型的所有更改.我想将所有更改保存到用户模型,但如果当前密码不正确,则不更改密码.我试过像这样拆分IF语句:

# Check if the user tried changing his/her password and CANNOT be authenticated with the entered current password
if !the_params[:password].blank? && !@user.authenticate(the_params[:current_password])
  # Add an error that states the user's current password is incorrect
  @user.errors.add(:base, "Current password is incorrect.")
end

# Try to update the user
if @user.update_attributes(the_params)
  # Notify the user that his/her profile was updated
  flash.now[:success] = "Your changes have been saved"
end
Run Code Online (Sandbox Code Playgroud)

这不起作用,因为即使当前密码不正确,用户也可以更改他/她的密码.单步执行代码时,虽然"当前密码不正确".@user在运行该update_attributes方法后,错误被添加到它似乎忽略此错误消息.

顺便说一下,该current_password字段是我的User模型中的虚拟属性:

attr_accessor :current_password
Run Code Online (Sandbox Code Playgroud)

我一直试图解决这个问题几个小时,所以我真的可以使用一些帮助.

谢谢!


感谢papirtiger,我得到了这个工作.我从他的回答中改变了一点代码.以下是我的代码.请注意,任何代码段都可以正常工作.

在用户模型中(user.rb)

class User < ActiveRecord::Base
  has_secure_password

  attr_accessor :current_password

  # Validate current password when the user is updated
  validate :current_password_is_correct, on: :update

  # Check if the inputted current password is correct when the user tries to update his/her password
  def current_password_is_correct
    # Check if the user tried changing his/her password
    if !password.blank?
      # Get a reference to the user since the "authenticate" method always returns false when calling on itself (for some reason)
      user = User.find_by_id(id)

      # Check if the user CANNOT be authenticated with the entered current password
      if (user.authenticate(current_password) == false)
        # Add an error stating that the current password is incorrect
        errors.add(:current_password, "is incorrect.")
      end
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

而我的用户控制器中的代码现在只是:

# Try to update the user
if @user.update_attributes(the_params)
  # Notify the user that his/her profile was updated
  flash.now[:success] = "Your changes have been saved"
end
Run Code Online (Sandbox Code Playgroud)

max*_*max 6

您可以在模型级别添加自定义验证,以检查密码是否已更改:

class User < ActiveRecord::Base
  has_secure_password

  validate :current_password_is_correct,
           if: :validate_password?, on: :update

  def current_password_is_correct
    # For some stupid reason authenticate always returns false when called on self
    if User.find(id).authenticate(current_password) == false
      errors.add(:current_password, "is incorrect.")
    end
  end

  def validate_password?
    !password.blank?
  end

  attr_accessor :current_password
end
Run Code Online (Sandbox Code Playgroud)