我的用户模型中包含此代码:
class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation
attr_accessor :password
before_save :encrypt_password
validates :email, :presence => true,
:uniqueness => { :case_sensitive => false },
:format => { :with => /\A[^@]+@[^@]+\z/ },
:length => 7..128
validates :password, :presence => true,
:confirmation => true,
:length => 6..128
private
def encrypt_password
return unless password
self.encrypted_password = BCrypt::Password.create(password)
end
end
当我用
更新某些用户字段时,现在在我的控制器中@user.update_attributes(params[:user])
密码字段始终有效,即使未在params散列中设置也是如此。我认为这是因为attr_accesor:密码总是在update_attributes上设置密码=“”。
现在我可以简单地跳过验证密码,如果它是一个空字符串:
validates :password, :presence => true,
:confirmation => true,
:length => 6..128,
:if => "password.present?"
但这不起作用,因为它允许用户设置一个空密码。
在我想要更改的字段上使用update_attribute不是解决方案,因为我需要对该属性进行验证。 如果我用
传入确切的参数@user.update_attributes(params[:user][:fieldname])
它无法解决问题,因为它还会触发密码验证。
是否有办法防止attr_accesor:密码总是在更新时设置密码=“”?
答案 0 :(得分:14)
新答案
这对我有用:
validates :password, :presence => true,
:confirmation => true,
:length => { :minimum => 6 },
:if => :password # only validate if password changed!
如果我没记错的话,我也花了一些时间才能做到这一点(很多试验和错误)。我从来没有时间找出其确切原因(与:if => "password.present?"
相反)。
旧答案 - 对您的目的并不实用(见评论) 我通过使用完全不同的密码更新操作(用户#update_password)解决了这个问题。现在只需验证密码字段
就足够了:on => [:create, :update_password]
(并且只允许这些操作访问)。
这里有更多细节:
在您的路线中:
resources :users do
member do
GET :edit_password # for the user#edit_password action
PUT :update_password # for the user#update_passwor action
end
end
在您的UsersController中:
def edit_password
# could be same content as #edit action, e.g.
@user = User.find(params[:id])
end
def update_password
# code to update password (and only password) here
end
在您的edit_password视图中,您现在拥有一个仅用于更新密码的表单,与编辑视图中的表单非常相似,但使用:method =&gt; :put和:url =&gt; edit_password_user_path(@user)
答案 1 :(得分:2)
我开始使用解决此问题的解决方案是:
开始使用ActiveModel的内置has_secure_password
方法。
在控制台
rails g migration add_password_digest_to_users password_digest:string
rake db:migrate
在你的模特中:
class User < ActiveRecord::Base
has_secure_password
attr_accessible :login_name, :password, :password_confirmation
# secure_password.rb already checks for presence of :password_digest
# so we can assume that a password is present if that validation passes
# and thus, we don't need to explicitly check for presence of password
validates :password,
:length => { :minimum => 6 }, :if => :password_digest_changed?
# secure_password.rb also checks for confirmation of :password
# but we also have to check for presence of :password_confirmation
validates :password_confirmation,
:presence=>true, :if => :password_digest_changed?
end
最后,
# In `config/locales/en.yml` make sure that errors on
# the password_digest field refer to "Password" as it's more human friendly
en:
hello: "Hello world"
activerecord:
attributes:
user:
password_digest: "Password"
哦,还有一件事:看railscast