2011-10-23 24 views
6

Tengo el siguiente modelo de usuario:rieles validar que password_confirmation está presente cuando la contraseña también está presente o se ha cambiado

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 

Estas validaciones no llegan a hacer lo que yo esperaba que lo harían. Es posible hacer lo siguiente:

# 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 

Así que lo que quiero es la siguiente:

  • contraseña requerida en crear, debe ser de 6 caracteres de largo
  • password_confirmation requerida en crear, debe coincidir con la contraseña
  • usuario no debería tener que enviar la contraseña al actualizar login_name
  • contraseña no puede ser borrado en la actualización

Algo que me confunde es que los carriles lanza un error de ningún método si uso password_changed? en contraposición a :password_digest_changed? en mi validación password_confirmation. No entiendo por qué.

Entonces, ¿alguien sabe lo que estoy haciendo mal aquí?

Respuesta

13

password no es una columna en la base de datos, ¿verdad? Solo un atributo?

Así que no hay ningún método password_changed?, que estaría disponible si password fuera una columna. En su lugar, debería verificar si password está configurado.

Algo así como:

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

Aunque se soluciona el problema inicial que tenías, todavía no es hacer lo que quiera, ya que sólo está comprobando la presencia, y que necesita que esté presente y contraseña del partido. Algo como lo siguiente debería funcionar (en combinación con la validación anterior).

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 

Si usted nunca ha visto :confirmation antes, es una validación estándar que busca foo y foo_confirmation y se asegura de que son la misma.

Tenga en cuenta que usted todavía tiene que comprobar la presencia de password_confirmation

+0

Ahh, tienes razón, contraseña y password_confirmation no son campos db modo que explica por qué no tengo acceso a los métodos sucios para ellos. El usuario aún puede eliminar su contraseña en la actualización y también puede acortarla a menos de 6 caracteres. Cuál es mi problema principal aquí – stephenmurdoch

+0

Lo he editado para abordar sus otras inquietudes. Parece que debería funcionar. – numbers1311407

+3

Gracias su código fue muy similar a lo que terminé usando. Al final pude eliminar la validación ': presence' porque' secure_password' ya verifica la presencia de ': password_digest'. Hice una [esencia] (https://gist.github.com/1308130) para recordarme a mí mismo en el futuro – stephenmurdoch

Cuestiones relacionadas