如何将更改密码与设备表单分离

10

我正在尝试完成两件事情:

1)更改Devise提供的默认“编辑用户表单”,删除“密码”并允许更新其他字段而无需输入密码,即删除密码的默认验证。

2)创建一个单独的表单来更改密码。

我已经使所有内容正常工作,只有一个问题,就是在用于更新密码的单独表单中,我包含了一个当前密码字段。但使用该表单时,没有对当前密码进行验证,因此我进行了更改。

@user.update_attributes(params[:user]) 

to

@user.update_with_password(params[:user])

这个方法可行,但引发了另一个问题。在主表单中,除密码外还有其他详细信息,现在该表单要求输入“当前密码”。如何实现这一点,而不需要在主表单上调用验证当前密码的函数呢?
以下是我的注册控制器:
def update
  @user = User.find(current_user.id)
  if @user.update_attributes(params[:user])
    set_flash_message :notice, :updated
    # Sign in the user bypassing validation in case his password changed
    sign_in @user, :bypass => true
    redirect_to after_update_path_for(@user)
  else
    clean_up_passwords(resource)
    respond_with_navigational(resource) do
      if params[:change_password] # or flash[:change_password]
        render :change_password
      else
        render :edit
      end
    end
  end
end

谢谢!

解决方案1

我已经找到了一个解决问题的方案(尽管很混乱):

def update
  @user = User.find(current_user.id)

  if params[:user][:password].blank?
    if @user.update_attributes(params[:user])
      set_flash_message :notice, :updated
      # Sign in the user bypassing validation in case his password changed
      sign_in @user, :bypass => true
      redirect_to after_update_path_for(@user)
    else
      respond_with_navigational(resource) do
        render :edit
      end
    end
  else
    if @user.update_with_password(params[:user])
      set_flash_message :notice, :updated
      # Sign in the user bypassing validation in case his password changed
      sign_in @user, :bypass => true
      redirect_to after_update_path_for(@user)
    else
      clean_up_passwords(resource)
      respond_with_navigational(resource) do
        render :change_password
      end
    end
  end

解决方案 2

你能提出更好的解决方案吗?

2个回答

6
被接受的答案并没有完全回答问题。 我相信问题是要为用户属性(如电子邮件,名字等)和密码设置单独的表格。以下是您需要执行的操作:
首先,利用Devise :: RegistrationsController进行配置文件更新。
- 自定义视图并删除“密码”和“确认密码”字段。如果在提交中不存在这些字段,则Devise会忽略它们。 - 如果您不想要求当前密码进行配置文件更改,请阅读此链接。不建议使用,不安全。
其次,创建自己的控制器来管理密码更新,并创建自己的助手来要求在更新时提供当前密码,密码和密码确认。
class PasswordsController < ApplicationController
  before_filter :authenticate_user!

  def edit
    @user = current_user
  end

  def update
    @user = User.find(current_user.id)
    if @user.update_password_with_password(user_params)
      # Sign in the user by passing validation in case their password changed
      sign_in @user, :bypass => true
      redirect_to edit_password_path, flash: { success: "Successfully updated password" }
    else
      render "edit"
    end

  end

  private

    def user_params
      params.require(:user).permit(:current_password, :password, :password_confirmation)
    end

end

这里是助手update_password_with_password,它将要求填写新密码字段。
class User < ActiveRecord::Base
  def update_password_with_password(params, *options)
    current_password = params.delete(:current_password)

    result = if valid_password?(current_password)
               update_attributes(params, *options)
             else
               self.assign_attributes(params, *options)
               self.valid?
               self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
               false
             end

    clean_up_passwords
    result
  end
end

1
我正在尝试遵循这个答案,但我有点新手,请问您能否添加应该与此解决方案一起使用的路由、视图和link_to吗?谢谢! - frcake
这个答案实现了密码更改和个人资料更改(不需要密码)的方式与Devise wiki推荐的方式相反。提供的链接建议创建一个单独的控制器来编辑非关键用户资料,可以安全地进行更改而无需提供密码。它还提供了一种替代方法,但不建议使用。因此,我认为推荐的方法是使用Devise注册控制器执行密码和/或电子邮件编辑,然后提供一个单独的控制器来编辑不需要密码的字段。 - OzBandit

5

是的,我已经看了两个,但我没有看到它们提供解决问题的方案。你能具体地给我展示一下吗? - Jeremy Lynch
你应该关注 @user.update_with_password(params[:user]) 和 @user.update_attributes(params[:user]) 的区别。 - Mike Szyndel
你能看一下我对上面问题的修改吗?它可以工作,但这是最好的方法吗? - Jeremy Lynch
为什么要尝试删除密码哈希密钥,如果它不存在?(前4行)。而且-更改密码和其他操作的代码是否相同? - Mike Szyndel
有很多重复的代码,我能想到的一个解决方案是类似于 update_result = ( params[:user][:password].blank? ? @user.update_attributes(params[:user]) : @user.update_with_password(params[:user]) ) 然后只需检查 false(这是两个更新不同之处)但这太丑陋了。 - Mike Szyndel
还有,你需要这个 if params[:change_password] 吗?用户仍然可以更新其他选项和密码吗?如果不需要,你可以将其删除。 - Mike Szyndel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接