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

时间:2011-10-23 00:00:42

标签: ruby-on-rails ruby-on-rails-3 activerecord

我有以下用户模型:

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

这些验证并不完全符合我的希望。可以执行以下操作:

# 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

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

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

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

所以有人知道我在这里做错了吗?

1 个答案:

答案 0 :(得分:13)

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

因此没有password_changed?方法,如果password是一列,则该方法可用。相反,您应该检查是否设置了password

类似的东西:

validates :password_confirmation, :presence => true, :if => '!password.nil?'

虽然这解决了您遇到的最初问题,但它仍然不会完全按照您的意愿行事,因为它只是检查状态,您需要它存在匹配密码。以下内容应该有效(与上述验证相结合)。

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

如果您之前从未见过:confirmation,那么这是一个标准验证,可以查找foofoo_confirmation,并确保它们是相同的。

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