2010-07-17 20 views
7

Tengo un modelo de usuario, con nombre de usuario, dirección de correo electrónico, contraseña, confirmación de contraseña, nombre, avatar (imagen), etc. Hay validaciones en los primeros 5, básicamente indicando que los 5 deben existir para crear un nuevo modelo.Rieles: atributos de actualización que se enfrentan con las validaciones

Sin embargo, esto me causa problemas cuando se trata de actualizaciones.

Tengo una página de edición, donde el usuario solo puede editar su nombre y avatar. Actualmente, no tengo la intención de permitirles cambiar su nombre de usuario, y deseo hacer un cambio de correo electrónico y contraseña desde una página diferente.

Así el formulario de edición tiene el siguiente aspecto:

<% form_for @user, :html => { :multipart => true } do |u| %> 
<p> 
    <label>Name:</label> 
    <%= u.text_field :name %> 
</p> 
<p> 
    <label>Avatar:</label> 
    <%= display_user_avatar %> 
    <%= u.file_field :avatar%> 
</p> 
<p> 
    <%= submit_tag %> 
</p> 
<% end %> 

Si intento hacer un @user.update_attributes(params[:user]), a continuación, ya que los únicos 2 params son name y avatar, la actualización falla, ya que cosas como contraseña, confirmación de la contraseña, correo electrónico, etc. son necesarios para validar la entrada, y simplemente no existen en esa forma.

Puedo solucionar esto haciendo @user.update_attribute(:name, params[:user][:name]), pero luego me preocupa si evitar las validaciones es algo bueno o no. Especialmente en lo que respecta a algo así como actualizaciones de contraseña, donde I do necesita validar la nueva contraseña.

¿Hay otra manera?

Y si yo fuera hacer esto simplemente utilizando update_attribute para :name y :avatar, ¿cómo voy a ir haciendo sobre él?

¿Funcionaría?

params[:user].each do |attribute| 
    @user.update_attribute(attribute, params[:user][attribute]) 
end 

¿Es esta una manera aceptable de hacer esto ...?


--edit como seguimiento -
Okie, me trató como usted sugiere y lo hizo

Así que está haciendo la versión !, y la excepción atrapado & que aparece en el navegador es decir:

Validation failed: Password is too short (minimum is 5 characters) 

la información en el registro del servidor es:

Processing UsersController#update (for 127.0.0.1 at 2010-07-18 11:56:59) [PUT] 
    Parameters: {"user"=>{"name"=>"testeeeeee"}, "commit"=>"Save changes", "action"=>"update", "_method"=>"put", "authenticity_token"=>"BMEGRW/pmIJVs1zlVH2TtZX2TQW8soeCXmMx4kquzMA=", "id"=>"tester", "controller"=>"users"} 

Urm. Al ver esto, me acabo de dar cuenta de que está enviando "id"=>"tester". Ahora, tengo mis rutas configuradas para que muestren el nombre de inicio de sesión de los usuarios, en lugar del user_id ... ¿Podría ser ese el motivo? Está intentando encontrar una actualización para un usuario con user_id == tester, pero dado que no existe, ¿intenta crear una en su lugar? ¿De verdad es algo que estoy haciendo mal debido a la ruta?

Hmmm ...rutas rastrillo me dice que la ruta es:

edit_user GET /users/:id/edit(.:format)        {:action=>"edit", :controller=>"users"} 
      PUT /users/:id(.:format)         {:action=>"update", :controller=>"users"} 

Y He definido la ruta de esa manera en el archivo user.rb:

def to_param 
    "#{login}" 
    end 

pero definitivamente ha estado mostrando login en lugar de id todo este tiempo. Pero también estoy haciendo lo correcto al comienzo de la acción de actualización, un @user = User.find_by_login(params[:id]), y luego actualizando ese @user.

Estoy muy confundido. >. <


Segunda actualización:

Mi User.rb cosas validación son los siguientes:

validates_length_of :login, :within => 3..20 
    validates_length_of :password, :within => 5..20 
    validates_presence_of :login, :email, :password, :password_confirmation, :salt, :name, :on => :create 
    validates_uniqueness_of :login, :case_sensitive => false 
    validates_confirmation_of :password 
    validates_format_of :email, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, :message => "format is invalid." 
    attr_accessor :password, :password_confirmation 

Y la sección hashed_password está aquí:

def password=(pass) 
    @password = pass 
    self.salt = User.random_string(10) if !self.salt? 
    self.hashed_password = User.encrypt(@password, self.salt) 
    end 

u.attributes me da

>> u.attributes 
=> {"salt"=>"NHpH5glxsU", "name"=>"test er", "avatar_updated_at"=>nil, "updated_at"=>Sat Jul 17 07:04:24 UTC 2010, "avatar_file_size"=>nil, "avatar_file_name"=>nil, "hashed_password"=>"84f8675c1ed43ef7f8645a375ea9f867c9a25c83", "id"=>1, "avatar_content_type"=>nil, "login"=>"tester", "email"=>"[email protected]", "created_at"=>Fri May 07 10:09:37 UTC 2010} 

Urmmm ... Ok, así que es lo que ha dicho, sobre el atributo virtual password estar realmente inexistente ... Entonces, ¿Cómo me manejo en que? Error, aquí pensé que estaba siendo inteligente manipulando mi propio código de autenticación ...

¿Qué tan fácil es cambiar a uno de esos complementos de autenticación? ¿Tendré que crear un nuevo modelo de usuario? ¿O debería el complemento poder trabajar con mi actual?

¡Gracias por toda la ayuda hasta ahora, por cierto! : D

+0

PD: Sí, el '

+0

Lo que describes no me suena del todo bien. Estoy bastante seguro de que si haces 'update_attributes' con un' Hash' que contiene solo un conjunto parcial de los atributos, entonces todos los otros atributos se quedan con sus valores anteriores significan que la validación no debe fallar. – mikej

Respuesta

10

He comprobado esto y una actualización parcial de solo 2 atributos a través de update_attributes funciona bien. Todos los demás atributos quedan con sus valores anteriores, lo que significa que la validación no debe fallar. Un par de cosas para probar:

  • ¿En su acción de controlador está cargando al usuario a través de User.find? es decir, ¿estás comenzando desde un modelo válido?
  • ¿Estás seguro de que la actualización está fallando debido a errores de validación? Intente reemplazar el update_attributes con update_attributes!. Este último lanzará una excepción si la actualización falla debido a la validación. O marque @user.errors después del intento de actualización para confirmar qué validación ha fallado.

actualización

Si User.find_by_login no encuentra un registro coincidente volverá nil y no crear un nuevo registro para usted. ¿Es posible que el usuario del probador en la base de datos tenga una contraseña demasiado corta? ¿Tal vez ese usuario fue creado antes de poner las validaciones en su código? ¿Está utilizando algún tipo de complemento o devolución de llamada para cifrar las contraseñas de los usuarios antes de guardar los registros?¿Es realmente password un atributo virtual que no se guarda y la contraseña real está en un campo como encrypted_password?

Pruebe esto desde script/console (utilizar el mismo entorno que se está probando la aplicación con - el desarrollo o producción)

> user = User.find_by_login 'tester' 
> user.valid? 
> user.attributes 

El user.valid? volverá true de false y le indicará si el usuario es válido para empezar con, incluso antes de intentar una actualización.

Actualización 2 (fijación de la validación)

En cuanto a la fijación de su propio código, se puede añadir un método como el siguiente para su modelo User:

def password_validation_required? 
    hashed_password.blank? || [email protected]? 
end 

y luego actualizar toda su reglas de validación relacionadas con la contraseña para que solo se apliquen si este método devuelve true, por ej.

validates_length_of :password, :within => 5..20, 
    :if => :password_validation_required? 

Lo que esto está diciendo es sólo hacer la regla de validación de contraseña si aún no tenemos un hashed_password (en un nuevo usuario, por ejemplo) o si una nueva contraseña en texto plano se ha especificado a través de password=. Si el usuario ya tiene una contraseña y no se modifica, omita la validación de la contraseña.

No obstante, tiene razón al considerar el uso de un complemento. Escribir su propio código de autenticación puede ser un ejercicio interesante y puede requerirse si tiene algunos requisitos inusuales. El inconveniente es que puede haber problemas de seguridad que no haya pensado. Volver a adaptar algo como restful_authentication a tu aplicación no debería ser tan malo. Es posible que solo necesite cambiar el nombre de uno o dos campos en su modelo User.

+0

Ok, acabo de actualizar la publicación original con los resultados de lo que he intentado. Y oh, cuando acabo de hacer 'update_attributes', con el flash mostrando' @users. errors', recibí un '#' en el flash, y eso fue todo. Lo que me hace preguntarme si realmente es un problema de la actualización donde 'id = tester' ... –

+0

@ Jty.tan respuesta actualizada con un poco más sugerencias. Déjame saber si alguno de ellos ayuda. – mikej

+0

oh. Tienes razón ... Hice un 'u.valid? 'y obtuve un' falso 'retorno. Hmmm ... Acabo de intentar con el último usuario que creé (con éxito), y obtuve un retorno falso también para 'válido?' ... ¿Es un problema con mi modelo de usuario y validaciones? Sí, mi contraseña de usuario está encriptada, y la contraseña encriptada es la que está guardada ... Volveré a actualizar con las validaciones de mi user.rb. –

Cuestiones relacionadas