当密码也存在或已被更改时,Rails验证password_confirmation存在

ste*_*och 6 activerecord ruby-on-rails ruby-on-rails-3

我有以下用户模型:

class User < ActiveRecord::Base
  # Users table has the necessary password_digest field
  has_secure_password
  attr_accessible :login_name, :password, :password_confirmation

  validates :login_name, :presence=>true, :uniqueness=>true

  # I run this validation on :create so that user 
  # can edit login_name without having to enter password      
  validates :password,:presence=>true,:length=>{:minimum=>6},:on=>:create

  # this should only run if the password has changed
  validates :password_confirmation, 
            :presence=>true, :if => :password_digest_changed?
end
Run Code Online (Sandbox Code Playgroud)

这些验证并不像我希望的那样完成.可以执行以下操作:

# rails console
u = User.new :login_name=>"stephen"
u.valid? 
# => false
u.errors 
# => :password_digest=>["can't be blank"], 
# => :password=>["can't be blank", "please enter at least 6 characters"]}

# so far so good, let's give it a password and a valid confirmation
u.password="password"
u.password_confirmation="password"

# at this point the record is valid and does save
u.save
# => true

# but we can now submit a blank password from console
u.password=""
# => true
u.password_confirmation=""
# => true

u.save
# => true
# oh noes
Run Code Online (Sandbox Code Playgroud)

所以我想要的是以下内容:

  • 创建时需要密码,长度必须为6个字符
  • create上需要password_confirmation,必须匹配密码
  • 用户不必在更新login_name时提交密码
  • 更新时无法删除密码

令我困惑的是,如果我使用rails 而不是在我的password_confirmation验证中,则会抛出无方法错误.我不明白为什么.password_changed?:password_digest_changed?

那么有谁知道我在这里做错了什么?

num*_*407 13

password不是数据库中的一列,对吗?只是一个属性?

所以没有password_changed?方法,如果password是一个列,它将是可用的.相反,你应该检查是否password设置完毕.

就像是:

validates :password_confirmation, :presence => true, :if => '!password.nil?'
Run Code Online (Sandbox Code Playgroud)

虽然这解决了你遇到的最初问题,但它仍然不会完全按照你想要的那样做,因为它只是检查存在,你需要它存在匹配密码.以下内容应该有效(与上述验证相结合).

validates :password, 
          # you only need presence on create
          :presence => { :on => :create },
          # allow_nil for length (presence will handle it on create)
          :length   => { :minimum => 6, :allow_nil => true },
          # and use confirmation to ensure they always match
          :confirmation => true
Run Code Online (Sandbox Code Playgroud)

如果你从来没有见过:confirmation之前,这是一个标准的验证,以查找foofoo_confirmation并确保它们是相同的.

请注意,您仍需要检查是否存在 password_confirmation

  • 谢谢你的代码非常接近我最终使用的.最后我能够删除`:presence`验证,因为`secure_password`已经检查了`:password_digest`的存在.我做了一个[gist](https://gist.github.com/1308130),以便将来提醒自己 (3认同)