目前,用户无需输入密码就可以编辑一些属性,因为我的验证设置如下:
validates :password, :presence =>true, :confirmation => true, :length => { :within => 6..40 }, :on => :create
validates :password, :confirmation => true, :length => { :within => 6..40 }, :on => :update, :unless => lambda{ |user| user.password.blank? }
但是,在用户执行此操作后,将删除其密码 - update_attributes将其密码更新为“”。这是我的更新定义:
def update
if @user.update_attributes(params[:user])
flash[:success] = "Edit Successful."
redirect_to @user
else
@title = "Edit user"
render 'edit'
end
end
我也尝试使用另一种使用update_attribute的定义:
def save_ff
@user = User.find(params[:id])
@user.update_attribute(:course1, params[:user][:course1] )
@user.update_attribute(:course2, params[:user][:course2] )
@user.update_attribute(:course3, params[:user][:course3] )
@user.update_attribute(:course4, params[:user][:course4] )
redirect_to @user
end
但出于某种原因,这是做同样的事情。如何在不更改密码的情况下更新某些用户属性?谢谢!
答案 0 :(得分:22)
我没有意识到我昨天给你的解决方案会导致这个问题。遗憾。
好了,获取灵感from devise,你应该这样简单地更新你的控制器:
def update
params[:user].delete(:password) if params[:user][:password].blank?
if @user.update_attributes(params[:user])
flash[:success] = "Edit Successful."
redirect_to @user
else
@title = "Edit user"
render 'edit'
end
end
答案 1 :(得分:12)
This blog post演示了你想要做的事情。
未显示但可能有用的是向模型添加访问者:
attr_accessor :new_password, :new_password_confirmation
attr_accessible :email, :new_password, :new_password_confirmation
并在用户提供新密码的条件下提供所有所需的验证。
validates :new_password, :presence => true,
:length => { :within => 6..40 },
:confirmation => true,
:if => :password_changed?
最后,我会添加一项检查,看看是否已设置encrypted_password以确定是否" password_changed?"为了在新记录上要求密码。
def password_changed?
!@new_password.blank? or encrypted_password.blank?
end
答案 2 :(得分:10)
我一直在努力解决这个问题并在圈子里转了一会儿,所以我想我已经把我的Rails 4解决方案放在这里了。
到目前为止,我所看到的答案都没有达到我的用例,它们似乎都涉及以某种方式绕过验证,但我希望能够验证其他字段以及密码(如果存在) 。另外,我没有在我的项目上使用设计,所以我无法利用任何特定的东西。
值得指出这是一个2部分问题:
步骤1 - 如果密码在控制器中是空白的,则需要从强参数中删除密码和确认字段:
if myparams[:password].blank?
myparams.delete(:password)
myparams.delete(:password_confirmation)
end
第2步 - 您需要更改验证,以便在未输入密码时验证密码。我们不想要的是将它设置为空白,这就是为什么我们之前从参数中删除它。
在我的情况下,这意味着在我的模型中将其作为验证:
validates :password, :presence => true, :confirmation => true, length: {minimum: 7}, :if => :password
请注意:if => :password - 跳过检查密码是否未设置。
答案 3 :(得分:5)
# It smells
def update
if params[:user][:password].blank?
params[:user].delete :password
params[:user].delete :password_confirmation
end
if @user.update_attributes(params[:user])
flash[:success] = "Edit Successful."
redirect_to @user
else
@title = "Edit user"
render 'edit'
end
end
# Refactoring
class User < ActiveRecord::Base
...
def update_attributes(params)
if params[:password].blank?
params.delete :password
params.delete :password_confirmation
super params
end
end
...
end
def update
if @user.update_attributes(params[:user])
flash[:success] = "Edit Successful."
redirect_to @user
else
@title = "Edit user"
render 'edit'
end
end
# And little better
class User < ActiveRecord::Base
...
def custom_update_attributes(params)
if params[:password].blank?
params.delete :password
params.delete :password_confirmation
update_attributes params
end
end
...
end
def update
if @user.custom_update_attributes(params[:user])
flash[:success] = "Edit Successful."
redirect_to @user
else
@title = "Edit user"
render 'edit'
end
end
答案 4 :(得分:4)
我遇到了同样的问题,上面的解决方案对我不起作用。在我的案例中,我找到了真正的罪魁祸首:我的用户模型中有一个encrypt_password回调,每次都将密码设置为空白。
before_save:encrypt_password
我通过在此回调中添加条件来修复它:
before_save:encrypt_password,:unless =&gt; Proc.new {| u | u.password.blank? }
答案 5 :(得分:3)
2017回答:
在 Rails 5 中,正如Michael Hartl的tutorial所指出的那样,你的模型中有以下几行:
validates :password, presence: true, length: { minimum: 6 }, allow_nil: true
allow_nil:true 是此处的关键,它允许用户编辑他/她的信息,而无需更改密码。
此时人们可能会认为这也会允许空用户注册;但是,使用自动验证密码存在但仅has_secure_password
方法的create
可以防止这种情况。
这是一个演示用户模型,用于说明目的:
class User < ApplicationRecord
attr_accessor :remember_token
before_save { self.email = email.downcase }
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
has_secure_password
validates :password, presence: true, length: { minimum: 6 }, allow_nil: true
.
.
.
end
我不知道如何用设计做到这一点。我的两分钱。
答案 6 :(得分:2)
正确答案不再适用于rails 4 。我相信我的答案是最干净的,并且最多才多艺的,只要您想省略任何属性(而不仅仅是密码),它就会起作用。如果要在多个不同的位置更新任何模型的单独属性,则需要使用此方法。
例如,如果您想要执行Stack Overflow所做的操作并通过security
页面更新密码,则可通过用户显示视图更新配置文件图像,并且可以更新用户的大量信息通过用户编辑视图。
1)使用类方法扩展hash class
以删除空值。我们将使用此方法删除未更新但仍存在于params散列中的空白值:
1a)在hash.rb
目录下的lib
目录下创建一个ext
文件:
命令行
$ mkdir lib/ext
$ touch lib/ext/hash.rb
1b)在hash.rb
内,&#39;创建&#39;一个Hash
类并创建一个.delete_blanks!
方法:
<强> LIB / EXT / hash.rb 强>
class Hash
def delete_blanks!
delete_if { |k, v| v.nil? }
end
end
1c)要求将此文件(以及整个lib目录)放入在初始化程序中引用它的rails中:
<强>配置/的boot.rb 强>
# other things such as gemfiles are required here, left out for brevity
Dir['lib/**/*.rb'].each { |f| load(f) } # requires all .rb files in the lib directory
2)在用户#update操作中,实现我们闪亮的新delete_blanks! class方法,用于删除我们未从params哈希更新的属性。然后,通过update_attributes
方法更新用户实例,*而不是update
方法!
2a)首先,让我们使用delete_blanks!修复user_params哈希的方法:
应用/控制器/ users_controller.rb 强>
new_params = user_params.delete_blanks!
2b)现在让我们使用update_attributes
方法更新实例,(同样,不是update
方法):
应用/控制器/ users_controller.rb 强>
@user.update_attributes(new_params)
以下是完成的users#update
操作的外观:
应用/控制器/ users_controller.rb 强>
def update
new_params = user_params.delete_blanks!
if @user.update_attributes(new_params)
redirect_to @user, notice: 'User was successfully updated.'
else
render action: 'edit' // or whatever you want to do
end
end
3)在User
模型中,为所有验证添加if: :<attribute>
选项。这是为了确保只有在params散列中存在属性时才会触发验证。我们的delete_blanks!
方法将从params哈希中删除该属性,因此例如,密码验证将无法运行。值得注意的是,delete_blanks!
仅删除值为 nil 的哈希条目,而不删除具有空字符串的哈希条目。因此,如果有人在用户创建表单(或任何带有密码字段的表单)上遗漏了密码,则状态验证将生效,因为哈希的密码输入不会为零,而是&#39;将是一个空字符串:
3a)在所有验证中使用if:
选项:
应用/模型/ user.rb 强>
VALID_EMAIL_REGEX = /[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9\-.]/
validates :first_name, presence: true, if: :first_name
validates :last_name, presence: true, if: :last_name
validates :user_name, presence: true, if: :user_name
validates :email, presence: true,
uniqueness: { case_sensitive: false },
format: { with: VALID_EMAIL_REGEX }, if: :email
validates :password, length: { minimum: 6, maximum: 10 }, if: :password
就是这样。现在,用户模型可以通过您的应用程序在许多不同的表单上进行更新。属性的存在验证仍然在包含其字段的任何表单上发挥作用,例如,密码在线验证仍会在user#create
视图中发挥作用。
这似乎比其他答案更冗长,但我相信这是最强大的方式。您可以在无限量的不同模型上单独更新User
个实例的无限数量的属性。请记住,当您想要使用新模型执行此操作时,需要重复步骤 2a), 2b)和 3a)
答案 7 :(得分:0)
@user.username=params[:username]
if @user.update_attribute(:email,params[:email])
flash[:notice]="successful"
else
flash[:notice]="fail"
end
上面的代码可以更新用户名和电子邮件字段。 因为update_attribute可以更新脏字段。 但很遗憾,update_attribute会跳过验证。
答案 8 :(得分:-1)
我遇到了同样的问题。我无法用
修复它params[:user].delete(:password) if params[:user][:password].blank?
我只能通过对每个项目单独执行“update_attribute”来实现它,例如。
if ( @user.update_attribute(:name, params[:user][:name]) &&
@user.update_attribute(:email, params[:user][:email]) &&
@user.update_attribute(:avatar, params[:user][:avatar]) &&
@user.update_attribute(:age, params[:user][:age]) &&
@user.update_attribute(:location, params[:user][:location]) &&
@user.update_attribute(:gender, params[:user][:gender]) &&
@user.update_attribute(:blurb, params[:user][:blurb]) )
flash[:success] = "Edit Successful."
redirect_to @user
else
@title = "Edit user info"
render 'edit'
end
这显然是一个彻头彻尾的黑客,但它是唯一可以解决它而不会弄乱验证并删除密码的方法!