无需密码即可更新“用户”属性
现在,用户可以编辑他们的一些属性,而无需输入密码,因为我的验证设置如下:
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
但由于某种原因,这是做同样的事情。如何在不更改密码的情况下更新某些用户属性?谢谢!
Right now, users can edit some their attributes without having to enter their password because my validations are set up like this:
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? }
However, after a user does this, their password is deleted - update_attributes is updating their password to "". Here is my update definition:
def update
if @user.update_attributes(params[:user])
flash[:success] = "Edit Successful."
redirect_to @user
else
@title = "Edit user"
render 'edit'
end
end
I've also tried using a different definition that uses update_attribute instead:
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
But for some reason this is doing the same thing. How can I update some user attributes without changing the password? Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
我没有意识到我昨天给你的解决方案会导致这个问题。对不起。
好吧,汲取灵感 从 devise 中,您应该这样简单地更新您的控制器:
I didn't realize the solution I gave you yesterday would lead to this problem. Sorry.
Well, taking inspiration from devise, you should simply update your controller this way:
这篇博文演示了您想要做的事情的原理。
未显示但可能有帮助的是向模型添加访问器:
并在用户提供新密码的情况下提供所有所需的验证。
最后,我会添加一个检查来查看是否已设置 crypto_password 以确定是否“password_changed?”为了要求新记录的密码。
This blog post demonstrates the principal of what you want to do.
What is not shown, but may be helpful, is to add accessors to the model:
and to provide all of the desired validation under the condition that the user has provided a new password.
Lastly, I would add a check to see if the encrypted_password has been set in order to determine if "password_changed?" in order to require a password on a new record.
我一直在努力解决这个问题,并且兜圈子有一段时间了,所以我想我应该把我的 Rails 4 解决方案放在这里。
到目前为止,我看到的答案都不符合我的用例,它们似乎都涉及以某种方式绕过验证,但我希望能够验证其他字段以及密码(如果存在)。另外,我没有在我的项目中使用 devise,所以我无法使用任何特定的东西。
值得指出的是,这是一个由两部分组成的问题:
步骤 1 - 如果密码为空,则需要从强参数中删除密码和确认字段,就像控制器中的那样:
步骤 2 - 您需要更改验证,以便密码是如果未输入则不会验证。我们不希望将其设置为空白,因此我们之前将其从参数中删除。
就我而言,这意味着将其作为我的模型中的验证:
请注意 :if =>; :password - 如果未设置密码则跳过检查。
I've been struggling with this and going around in circles for a while, so I thought I'd put my Rails 4 solution here.
None of the answers I've seen so far meet my use case, they all seem to involve bypassing validation in some way, but I want to be able to validate the other fields and also the password (if present). Also I'm not using devise on my project so i can't make use of anything particular to that.
Worth pointing out that it's a 2 part problem:
Step 1 - you need to remove the password and confirmation field from the strong parameters if the password is blank like so in your controller:
Step 2 - you need to alter validation such that the password isn't validated if it's not entered. What we don't want is for it to be set to blank, hence why we removed it from our parameters earlier.
In my case this means having this as the validation in my model:
Note the :if => :password - skip checking if the password is not being set.
2017 年答案:
在 Rails 5 中,Michael Hartl 的 教程,您在模型中获得以下内容就足够了:
allow_nil: true 是这里的关键。这允许用户编辑他/她的信息,而无需更改密码。
此时人们可能会认为这也将允许空用户注册;但是,可以通过使用 仅在
create
方法中自动验证密码是否存在。这是一个用于说明目的的演示
User
模型:不幸的是,我不知道如何在设计中实现此功能。
干杯
2017 answer:
In Rails 5 as also pointed out by Michael Hartl's tutorial, it's enought that you get something along these lines in your model:
allow_nil: true is the key here. This allows a user to edit his/her info without expecting to also change the password.
At this point people may think that this will also allow empty user signups; However this is prevented by using the
has_secure_password
which automatically validates password presence exclusively within thecreate
method.This is a demo
User
model for illustration purposes:Unfortunately I've no clue how to make this work in devise.
Cheers ????.
我遇到了同样的问题,上面的解决方案对我不起作用。我发现我的案例中真正的罪魁祸首是:我的用户模型中有一个 encrypt_password 回调,每次都将密码设置为空白。
before_save :encrypt_password
我通过在此回调的末尾添加一个条件来修复它:
before_save :encrypt_password, :unless => Proc.new { |u| u.密码.空白? }
I had the same problem, and the solutions above didn't work for me. I found the real culprit in my case: I had an encrypt_password callback in my User model, which was setting the password to blank each time.
before_save :encrypt_password
I fixed it by adding a condition at the end for this call back:
before_save :encrypt_password, :unless => Proc.new { |u| u.password.blank? }
正确答案不再适用于 Rails 4。我相信我的答案是最干净且最通用的,每当您想省略任何属性(不仅仅是密码)时,它都会起作用。如果您想在多个不同位置更新任何模型的单独属性,则需要这种方法。
例如,如果您想要执行 Stack Overflow 所做的操作,并通过
安全
页面更新密码、通过用户显示视图更新个人资料图像以及通过用户编辑更新大量用户信息看法。1) 使用类方法扩展
哈希类
以删除空白值。我们将使用此方法删除未更新但仍存在于 params 哈希中的空白值:1a) 创建一个
hash.rb
文件您的lib
目录,位于ext
目录下:命令行
1b) 内部
hash.rb,'创建'一个
Hash
类并创建.delete_blanks!
方法:lib/ext/hash.rb
1c) 需要此文件(以及您的整个 lib 目录)到在初始化程序中引用它的 Rails 中:
config/boot.rb
2) 在 users#update 操作中,实现我们闪亮的新 delete_blanks!类方法来删除我们不从 params 哈希中更新的属性。然后,通过
update_attributes
方法更新用户实例,*不是update
方法!2a) 首先,让我们使用 delete_blanks !修复 user_params 哈希的方法:
app/controllers/users_controller.rb
2b) 现在让我们使用
update_attributes
方法更新实例,(再次,而不是update
方法):app/controllers/users_controller.rb
这是完成的
users#update
操作的样子看看:app/controllers/users_controller.rb
3) 在
User
模型中,添加if: :<所有验证的 attribute>
选项。这是为了确保仅当属性存在于 params 哈希中时才会触发验证。我们的delete_blanks!
方法将从 params 哈希中删除该属性,因此不会运行密码验证等操作。还值得注意的是,delete_blanks!
仅删除值为 nil 的哈希条目,而不是那些空字符串的哈希条目。因此,如果有人在用户创建表单(或任何带有密码字段的表单)上遗漏了密码,则存在验证将生效,因为哈希的 :password 条目不会为零,它将是一个空string:3a) 在所有验证中使用
if:
选项:app/models/user.rb
就是这样。现在,用户模型可以在您的应用程序中通过许多不同的形式进行更新。属性的存在验证仍然会在包含该属性字段的任何表单上发挥作用,例如,密码存在验证仍然会在
user#create
视图中发挥作用。这可能看起来比其他答案更冗长,但我相信这是最可靠的方法。您可以在无限数量的不同模型上单独更新
User
实例的无限数量的属性。请记住,当您想对新模型执行此操作时,您需要重复步骤2a)、2b)和3a)The correct answer no-longer works for rails 4. I believe my answer is the cleanest and the most versatile that will work whenever you want to leave out any attributes (not just the password). This approach will be needed if you want to update the separate attributes of any model in a number of different places.
For example, if you want to do what Stack Overflow does and have the passwords updatable via a
security
page, the profile image updatable via the user show view and the bulk of a user's information updatable via a user edit view.1) Extend the
hash class
with a class method to delete blank values. We will use this method to remove blank values that are not being updated but are still present in the params hash:1a) Create a
hash.rb
file in yourlib
directory, under anext
directory:command line
1b) Inside
hash.rb
, 'create' aHash
class and create a.delete_blanks!
method:lib/ext/hash.rb
1c) Require this file (and your entire lib directory) into the rails referencing it in an initializer:
config/boot.rb
2) Inside the users#update action, implement our shiny new delete_blanks! class method to remove the attributes we're not updating from the params hash. Then, update the user instance via the
update_attributes
method, *not theupdate
method!2a) Firstly, let's use the delete_blanks! method to fix our user_params hash:
app/controllers/users_controller.rb
2b) And now let's update the instance using the
update_attributes
method, (again, not theupdate
method):app/controllers/users_controller.rb
Here's how the finished
users#update
action should look:app/controllers/users_controller.rb
3) In the
User
model, add theif: :<attribute>
option to all of your validations. This is to make sure the validation is only triggered if the attribute is present in the params hash. Ourdelete_blanks!
method will have removed the attribute from the params hash, so the validation for password, for example, won't be run. It's also worth noting thatdelete_blanks!
only removes hash entries with a value of nil, not those with empty strings. So if someone leaves out the password on the user create form (or any form with a field for the password), a presence validation will take effect because the :password entry of the hash won't be nil, it'll be an empty string:3a) Use the
if:
option on all validations:app/models/user.rb
And that's it. Now the user model can be updated over many, many different forms all over your app. Presence validations for an attribute still come into play on any form that contains a field for it, e.g. the password presence validation still would come into play in the
user#create
view.This may seem more verbose than other answers, but I believe this is the most robust way. You can update in isolation an infinite number of attributes for
User
instances, on an infinite amount of different models. Just remember when you want to do this with a new model you need to repeat the steps 2a), 2b) and 3a)上面的代码可以更新用户名和电子邮件字段。
因为update_attribute可以更新脏字段。
但遗憾的是,update_attribute 会跳过验证。
above code can update username and email field.
because update_attribute can update dirty fields.
but it is a pity, update_attribute would skip validation.
我也遇到了同样的问题。我无法修复它,
我只能通过对每个项目单独执行“update_attribute”来使其工作,例如,
这显然是一个彻底的黑客攻击,但这是我可以在不弄乱的情况下弄清楚它的唯一方法验证并删除密码!
I was having the same problem. I wasn't able to fix it with
I have only been able to get it to work by doing "update_attribute" on each item individually, e.g.
which is clearly a total hack but its the only way I can figure it out without messing with the validations and deleting the password!