validator validates_presence_of validates rails method greater_than custom create ruby-on-rails validation passwords update-attributes

ruby on rails - validates_presence_of - Actualizando los atributos de "Usuario" sin requerir contraseña



rails validates if (9)

En este momento, los usuarios pueden editar algunos de sus atributos sin tener que ingresar su contraseña porque mis validaciones están configuradas de esta manera:

validates :password, :presence =>true, :confirmation => true, :length => { :within => 6..40 }, :on => :create validates :password, :confirmation => true, :length => { :within => 6..40 }, :on => :update, :unless => lambda{ |user| user.password.blank? }

Sin embargo, después de que un usuario haga esto, su contraseña se elimina - update_attributes está actualizando su contraseña a "". Aquí está mi definición de actualización:

def update if @user.update_attributes(params[:user]) flash[:success] = "Edit Successful." redirect_to @user else @title = "Edit user" render ''edit'' end end

También he intentado usar una definición diferente que usa update_attribute en su lugar:

def save_ff @user = User.find(params[:id]) @user.update_attribute(:course1, params[:user][:course1] ) @user.update_attribute(:course2, params[:user][:course2] ) @user.update_attribute(:course3, params[:user][:course3] ) @user.update_attribute(:course4, params[:user][:course4] ) redirect_to @user end

Pero por alguna razón esto está haciendo lo mismo. ¿Cómo puedo actualizar algunos atributos de usuario sin cambiar la contraseña? ¡Gracias!


Estaba teniendo el mismo problema. No pude arreglarlo con

params[:user].delete(:password) if params[:user][:password].blank?

Solo he podido hacer que funcione haciendo "update_attribute" en cada elemento individualmente, por ejemplo

if ( @user.update_attribute(:name, params[:user][:name]) && @user.update_attribute(:email, params[:user][:email]) && @user.update_attribute(:avatar, params[:user][:avatar]) && @user.update_attribute(:age, params[:user][:age]) && @user.update_attribute(:location, params[:user][:location]) && @user.update_attribute(:gender, params[:user][:gender]) && @user.update_attribute(:blurb, params[:user][:blurb]) ) flash[:success] = "Edit Successful." redirect_to @user else @title = "Edit user info" render ''edit'' end

que es claramente un hack total, pero es la única forma en que puedo resolverlo sin alterar las validaciones y eliminando la contraseña.


He estado luchando con esto y dando vueltas en círculos por un tiempo, así que pensé en poner mi solución Rails 4 aquí.

Ninguna de las respuestas que he visto hasta ahora satisfacen mi caso de uso, todas parecen implicar eludir la validación de alguna manera, pero quiero poder validar los otros campos y también la contraseña (si está presente). Además, no uso dispositivos en mi proyecto, por lo que no puedo hacer uso de nada en particular.

Vale la pena señalar que es un problema de 2 partes:

Paso 1: debe eliminar la contraseña y el campo de confirmación de los parámetros seguros si la contraseña está en blanco, como en su controlador:

if myparams[:password].blank? myparams.delete(:password) myparams.delete(:password_confirmation) end

Paso 2: debe modificar la validación para que la contraseña no se valide si no se ingresa. Lo que no queremos es que se establezca en blanco, por lo que lo eliminamos de nuestros parámetros anteriormente.

En mi caso, esto significa tener esto como la validación en mi modelo:

validates :password, :presence => true, :confirmation => true, length: {minimum: 7}, :if => :password

Tenga en cuenta: if =>: password: omita la comprobación si la contraseña no se está configurando.


No me di cuenta de que la solución que te di ayer llevaría a este problema. Lo siento.

Bien, inspirándose en el diseño , simplemente debe actualizar su controlador de esta manera:

def update params[:user].delete(:password) if params[:user][:password].blank? if @user.update_attributes(params[:user]) flash[:success] = "Edit Successful." redirect_to @user else @title = "Edit user" render ''edit'' end end


Tuve el mismo problema, y ​​las soluciones anteriores no funcionaron para mí. Encontré al verdadero culpable en mi caso: tuve una devolución de llamada encrypt_password en mi modelo de Usuario, que estaba configurando la contraseña en blanco cada vez.

before_save: encrypt_password

Lo arreglé agregando una condición al final para esta llamada:

before_save: encrypt_password,: menos => Proc.new {| u | u.password.blank? }


Esta entrada de blog demuestra el principio de lo que quieres hacer.

Lo que no se muestra, pero puede ser útil, es agregar accesores al modelo:

attr_accessor :new_password, :new_password_confirmation attr_accessible :email, :new_password, :new_password_confirmation

y para proporcionar toda la validación deseada bajo la condición de que el usuario haya proporcionado una nueva contraseña.

validates :new_password, :presence => true, :length => { :within => 6..40 }, :confirmation => true, :if => :password_changed?

Por último, agregaría una verificación para ver si se ha establecido la contraseña cifrada para determinar si "¿cambio de contraseña?" para requerir una contraseña en un nuevo registro.

def password_changed? !@new_password.blank? or encrypted_password.blank? end


2017 respuesta:

En Rails 5 como también lo indica el tutorial Michael Hartl, es suficiente que tengas algo parecido a esto en tu modelo:

validates :password, presence: true, length: { minimum: 6 }, allow_nil: true

allow_nil: true es la clave aquí que le permite a un usuario editar su información sin requerir también un cambio de contraseña.

En este punto, se podría pensar que esto también permitirá registros de usuarios vacíos; Sin embargo, esto se evita mediante el uso de has_secure_password que valida automáticamente la presencia de la contraseña, pero solo el método de create .

Este es un modelo de usuario de demostración con fines ilustrativos:

class User < ApplicationRecord attr_accessor :remember_token before_save { self.email = email.downcase } validates :name, presence: true, length: { maximum: 50 } VALID_EMAIL_REGEX = //A[/w+/-.]+@[a-z/d/-.]+/.[a-z]+/z/i validates :email, presence: true, length: { maximum: 255 }, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false } has_secure_password validates :password, presence: true, length: { minimum: 6 }, allow_nil: true . . . end

No tengo ni idea de cómo hacer esto con el dispositivo. Mis dos centavos.


La respuesta correcta ya no funciona para rieles 4 . Creo que mi respuesta es la más limpia y la más versátil que funcionará siempre que desee omitir atributos (no solo la contraseña). Este enfoque será necesario si desea actualizar los atributos separados de cualquier modelo en diferentes lugares.

Por ejemplo, si desea hacer lo que hace y tener las contraseñas actualizables a través de una página de security , la imagen del perfil actualizable a través de la vista de usuario y la mayor parte de la información de un usuario actualizable a través de una vista de edición de usuario.

1) Extienda la hash class con un método de clase para eliminar valores en blanco. Usaremos este método para eliminar los valores en blanco que no se están actualizando pero que aún están presentes en el hash params:

1a) Cree un archivo hash.rb en su directorio lib , bajo un directorio ext :

línea de comando

$ mkdir lib/ext $ touch lib/ext/hash.rb

1b) Dentro de hash.rb , ''crea'' una clase Hash y crea un .delete_blanks! método:

lib / ext / hash.rb

class Hash def delete_blanks! delete_if { |k, v| v.nil? } end end

1c) Requerir este archivo (y todo su directorio lib) en los rieles que lo referencian en un inicializador:

config / boot.rb

# other things such as gemfiles are required here, left out for brevity Dir[''lib/**/*.rb''].each { |f| load(f) } # requires all .rb files in the lib directory

2) Dentro de la acción de actualización # de los usuarios, ¡implemente nuestro nuevo nuevo delete_blanks! Método de clase para eliminar los atributos que no estamos actualizando del hash params. Luego, actualice la instancia de usuario a través del método update_attributes , * no el método de update !

2a) En primer lugar, ¡usemos delete_blanks! Método para arreglar nuestro hash user_params:

app / controllers / users_controller.rb

new_params = user_params.delete_blanks!

2b) Y ahora, actualicemos la instancia utilizando el método update_attributes , (nuevamente, no el método de update ):

app / controllers / users_controller.rb

@user.update_attributes(new_params)

Aquí es cómo debe verse la acción de users#update finalizados:

app / controllers / users_controller.rb

def update new_params = user_params.delete_blanks! if @user.update_attributes(new_params) redirect_to @user, notice: ''User was successfully updated.'' else render action: ''edit'' // or whatever you want to do end end

3) En el modelo de User , agregue la opción if: :<attribute> a todas sus validaciones. Esto es para asegurarse de que la validación solo se active si el atributo está presente en el hash params. ¡Nuestros delete_blanks! El método habrá eliminado el atributo del hash params, por lo que la validación de la contraseña, por ejemplo, no se ejecutará. También vale la pena señalar que delete_blanks! solo elimina las entradas de hash con un valor de nil , no aquellas con cadenas vacías. Entonces, si alguien omite la contraseña en el formulario de creación del usuario (o cualquier formulario con un campo para la contraseña), la validación de la presencia tendrá efecto porque: la entrada de contraseña del hash no será nula, estará vacía cuerda:

3a) Use la opción if: en todas las validaciones:

aplicación / modelos / usuario.rb

VALID_EMAIL_REGEX = /[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+/.[a-zA-Z0-9/-.]/ validates :first_name, presence: true, if: :first_name validates :last_name, presence: true, if: :last_name validates :user_name, presence: true, if: :user_name validates :email, presence: true, uniqueness: { case_sensitive: false }, format: { with: VALID_EMAIL_REGEX }, if: :email validates :password, length: { minimum: 6, maximum: 10 }, if: :password

Y eso es. Ahora, el modelo de usuario se puede actualizar en muchas, muchas formas diferentes en toda su aplicación. Las validaciones de presencia para un atributo aún entran en juego en cualquier formulario que contenga un campo para él, por ejemplo, la validación de presencia de contraseña todavía entraría en juego en la vista de user#create .

Esto puede parecer más detallado que otras respuestas, pero creo que esta es la forma más sólida. Puede actualizar de forma aislada un número infinito de atributos para instancias de User , en una cantidad infinita de modelos diferentes. Solo recuerde que cuando quiera hacer esto con un nuevo modelo, debe repetir los pasos 2a) , 2b) y 3a)


# It smells def update if params[:user][:password].blank? params[:user].delete :password params[:user].delete :password_confirmation end if @user.update_attributes(params[:user]) flash[:success] = "Edit Successful." redirect_to @user else @title = "Edit user" render ''edit'' end end # Refactoring class User < ActiveRecord::Base ... def update_attributes(params) if params[:password].blank? params.delete :password params.delete :password_confirmation super params end end ... end def update if @user.update_attributes(params[:user]) flash[:success] = "Edit Successful." redirect_to @user else @title = "Edit user" render ''edit'' end end # And little better class User < ActiveRecord::Base ... def custom_update_attributes(params) if params[:password].blank? params.delete :password params.delete :password_confirmation update_attributes params end end ... end def update if @user.custom_update_attributes(params[:user]) flash[:success] = "Edit Successful." redirect_to @user else @title = "Edit user" render ''edit'' end end


@user.username=params[:username] if @user.update_attribute(:email,params[:email]) flash[:notice]="successful" else flash[:notice]="fail" end

El código anterior puede actualizar el nombre de usuario y el campo de correo electrónico. porque update_attribute puede actualizar campos sucios. pero es una pena, update_attribute omitiría la validación.