Rails + 设计:使用或不使用密码更新用户
Rails + Devise: Update user with or without pasword
有很多相关问题:
- Devise: Update Account without password confirmation
- rails: devise update user without password
- Devise 3 (rails 4) can't update user without password
- 等...
但是当我尝试使用他们的答案时,我从来没有得到我想要的,所以我决定 post 这种问答方式。
情况:
我正在研究 Rails app using devise and I wanted a "Manage Profile form." I wanted one form for updating user information, including email and password, but also first_name, last_name, and other non-devise fields. I only wanted to require the password fields (password and password_confirmation) if the user was trying to change their password. I also wanted to build my form with the form_for 助手,并将用户能够更新的字段列入白名单。而且我还想要来自 devise 的所有方便的错误消息(例如,"Your password must be at least 8 characters." 或任何它们)。
TL;DR:剥离 params
只为你想要的,我称之为 user_params
。在处理表单的操作中检查 user_params[:password]
是否为空,如果它尝试用 @user.update_without_password(user_params)
更新你的 @user
模型,如果它没有尝试用 [=20= 更新].如适用更新调用returnsfalse
@user.errors
持有说明。
我是这样解决这个问题的:
我在 config/routes
文件中定义了一个 resource
:
resource :profile
我为我的资源创建了一个控制器,它扩展了设计的经过身份验证的控制器 ProfilesController < AuthenticatedController
以管理配置文件。配置文件控制器包含几个方法
包括 user_params
,它主要将 params
过滤到白名单:
def user_params
accessible = [
:first_name,
:last_name,
:email,
:password,
:password_confirmation
]
params.require(:user).permit(accessible)
end
和 update
处理表格的业务:
def update
# current_user holds the logged in user
@user = current_user
# IF they've left the password field blank,
# AND the devise update_without_password method returns true
# OR IF a full update of user (including password and password_confirmation) returns true
# THEN re-sign them in to flush their session, and redirect them back to their dashboard, and send a success message.
# ELSE re-present the edit form they were just on (there's a handy catcher
# in the edit view script to render the form errors, you can find them on
# @user.errors)
if (user_params[:password].blank? && @user.update_without_password(user_params)) || @user.update(user_params)
sign_in(@user, bypass: true)
redirect_to '/dashboard', notice: 'Your profile changes have been saved.'
else
render 'edit'
end
end
当然还有一个视图脚本(在我的例子中是一个 haml 脚本 - app/views/profiles/edit.html.haml
)使用 form_for
呈现表单:
= form_for current_user, as: :user, url: profile_path, html: { class: '' } do |f|
# [f.label, f.text_field, f.password_field, etc...]
我的用户模型也包含所有设计优点:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :receipts
validate :first_name, presence: true
validate :last_name, presence: true
validate :email, presence: true, email: true
end
如果你真的想在没有 current_password 的情况下更新密码,那么你需要使用用户 reset_password
方法
@user.reset_password(params[:user][:password], params[:user][:password_confirmation])
这是适用于所有情况的问题的完整解决方案:
if params.dig(:user, :password).blank?
updated = @user.update_without_password(params[:user].to_unsafe_hash)
else
if params.dig(:user, :current_password).nil?
@user.reset_password(params[:user][:password], params[:user][:password_confirmation])
updated = @user.update_without_password(params[:user].to_unsafe_hash)
else
updated = @user.update_with_password(params[:user].to_unsafe_hash)
end
bypass_sign_in(@user)
end
有很多相关问题:
- Devise: Update Account without password confirmation
- rails: devise update user without password
- Devise 3 (rails 4) can't update user without password
- 等...
但是当我尝试使用他们的答案时,我从来没有得到我想要的,所以我决定 post 这种问答方式。
情况:
我正在研究 Rails app using devise and I wanted a "Manage Profile form." I wanted one form for updating user information, including email and password, but also first_name, last_name, and other non-devise fields. I only wanted to require the password fields (password and password_confirmation) if the user was trying to change their password. I also wanted to build my form with the form_for 助手,并将用户能够更新的字段列入白名单。而且我还想要来自 devise 的所有方便的错误消息(例如,"Your password must be at least 8 characters." 或任何它们)。
TL;DR:剥离 params
只为你想要的,我称之为 user_params
。在处理表单的操作中检查 user_params[:password]
是否为空,如果它尝试用 @user.update_without_password(user_params)
更新你的 @user
模型,如果它没有尝试用 [=20= 更新].如适用更新调用returnsfalse
@user.errors
持有说明。
我是这样解决这个问题的:
我在 config/routes
文件中定义了一个 resource
:
resource :profile
我为我的资源创建了一个控制器,它扩展了设计的经过身份验证的控制器 ProfilesController < AuthenticatedController
以管理配置文件。配置文件控制器包含几个方法
包括 user_params
,它主要将 params
过滤到白名单:
def user_params
accessible = [
:first_name,
:last_name,
:email,
:password,
:password_confirmation
]
params.require(:user).permit(accessible)
end
和 update
处理表格的业务:
def update
# current_user holds the logged in user
@user = current_user
# IF they've left the password field blank,
# AND the devise update_without_password method returns true
# OR IF a full update of user (including password and password_confirmation) returns true
# THEN re-sign them in to flush their session, and redirect them back to their dashboard, and send a success message.
# ELSE re-present the edit form they were just on (there's a handy catcher
# in the edit view script to render the form errors, you can find them on
# @user.errors)
if (user_params[:password].blank? && @user.update_without_password(user_params)) || @user.update(user_params)
sign_in(@user, bypass: true)
redirect_to '/dashboard', notice: 'Your profile changes have been saved.'
else
render 'edit'
end
end
当然还有一个视图脚本(在我的例子中是一个 haml 脚本 - app/views/profiles/edit.html.haml
)使用 form_for
呈现表单:
= form_for current_user, as: :user, url: profile_path, html: { class: '' } do |f|
# [f.label, f.text_field, f.password_field, etc...]
我的用户模型也包含所有设计优点:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :receipts
validate :first_name, presence: true
validate :last_name, presence: true
validate :email, presence: true, email: true
end
如果你真的想在没有 current_password 的情况下更新密码,那么你需要使用用户 reset_password
方法
@user.reset_password(params[:user][:password], params[:user][:password_confirmation])
这是适用于所有情况的问题的完整解决方案:
if params.dig(:user, :password).blank?
updated = @user.update_without_password(params[:user].to_unsafe_hash)
else
if params.dig(:user, :current_password).nil?
@user.reset_password(params[:user][:password], params[:user][:password_confirmation])
updated = @user.update_without_password(params[:user].to_unsafe_hash)
else
updated = @user.update_with_password(params[:user].to_unsafe_hash)
end
bypass_sign_in(@user)
end