2011-08-23 15 views
5

Tengo el siguiente en mi modelo de usuariovalidar y actualizar único atributo carriles

attr_accessible :avatar, :email 

validates_presence_of :email 
has_attached_file :avatar # paperclip 

validates_attachment_size :avatar, 
          :less_than => 1.megabyte, 
          :message => 'Image cannot be larger than 1MB in size', 
          :if => Proc.new { |imports| !imports.avatar_file_name.blank? } 

en una de mis reguladores, sólo quiero actualizar y validar el campo avatar sin actualizar y validar correo electrónico.

¿Cómo puedo hacer esto?

por ejemplo (esto no funcionará)

if @user.update_attributes(params[:user]) 
# do something... 
end 

También probé con update_attribute('avatar', params[:user][:avatar]), pero que saltaría las validaciones de campo avatar también.

+1

¿Duplicado? http://stackoverflow.com/questions/457239/is-there-a-way-to-validate-a-specific-attribute-on-an-activerecord-without-instan/457313#457313 –

+0

no, creo que 'simulacro .valid? 'valida todo. Estoy buscando validar solo un atributo. – Madhusudhan

Respuesta

13

Puede validate the attribute by hand y usar update_attribute, que skips validation. Si se agrega this to your User:

def self.valid_attribute?(attr, value) 
    mock = self.new(attr => value) 
    if mock.valid? 
    true 
    else 
    !mock.errors.has_key?(attr) 
    end 
end 

y luego actualizar el atributo de esta manera:

if(!User.valid_attribute?('avatar', params[:user][:avatar]) 
    # Complain or whatever. 
end 
@user.update_attribute('avatar', params[:user][:avatar]) 

se debe obtener la atributo único actualizado mientras que sólo el (manualmente) la validación de ese atributo.

Si observa cómo funciona el valid_attribute? de Milan Novota, verá que realiza las validaciones y luego verifica si el específico attr tenía problemas; no importa si alguna de las otras validaciones falló, como valid_attribute? solo mira las fallas de validación para el atributo que le interesa.

Si va a hacer muchas de estas cosas, entonces podría agregue un método al usuario:

def update_just_this_one(attr, value) 
    raise "Bad #{attr}" if(!User.valid_attribute?(attr, value)) 
    self.update_attribute(attr, value) 
end 

y úselo para actualizar su único atributo.

+0

esto también verificaría las validaciones de correo electrónico, simplemente no avatar. – Madhusudhan

+0

@Madhusudhan: puede configurar la validación a mano y usar 'update_attribute'. Por favor mira mi actualización –

+0

yup que ayudó! ¡Gracias! – Madhusudhan

1

¿Has intentado poner una condición en el validates_presence_of :email?

http://ar.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#M000083

opciones de configuración:

si - Especifica un método, proc o cuerda para llamar a determinar si debe producirse la validación (por ejemplo: si =>: allow_validation, o bien: si => Proc.new {| user | user.signup_step> 2}). El método, proc o cadena debe devolver o evaluar a un valor verdadero o falso.

unless - Especifica un método, proc o cadena para llamar para determinar si la validación no debería ocurrir (por ejemplo: unless =>: skip_validation, o: unless => Proc.new {| user | user.signup_step < = 2 }). El método, proc o cadena debe devolver o evaluar a un valor verdadero o falso.

1

Supongo que necesita esto, porque tiene un asistente de pasos múltiples, donde primero carga el avatar y el correo electrónico se completa más tarde.

Que yo sepa, con sus validaciones tal como están, no veo una buena solución de trabajo. O valida todo, o actualiza el avatar sin validaciones.Si fuera un atributo simple, podría verificar si el nuevo valor pasa la validación por separado y luego actualizar el modelo sin validaciones (por ejemplo, usando update_attribute).

puedo sugerir dos enfoques alternativos posibles:

  • ya sea a asegurarse de que la dirección de correo siempre se entró por primera vez, que creo que no es una mala solución. Y luego, con cada guardado, se cumple la validación.
  • de lo contrario, cambie la validación. ¿Por qué declararía una validación en un modelo si hay registros en la base de datos que no cumplen con la validación? Eso es muy contrario a la intuición.

Así que me gustaría proponer algo como esto:

validate :presence_of_email_after_upload_avatar 

def presence_of_email_after_upload_avatar 
    # write some test, when the email should be present 
    if avatar.present? 
    errors.add(:email, "Email is required") unless email.present? 
    end 
end 

Espero que esto ayude.

+0

errors.add (: email, "Se requiere correo electrónico") genera error = "Se requiere correo electrónico por correo electrónico". Cambiar "Se requiere correo electrónico" para solo "se requiere" –

6

A condición?

validates_presence_of :email, :if => :email_changed? 
1

Aquí está mi solución. Mantiene el mismo comportamiento que .valid? método, la bruja devuelve verdadero o falso y agrega errores en el modelo en el momento en que se llamó.

class MyModel < ActiveRecord::Base 
    def valid_attributes?(attributes) 
    mock = self.class.new(self.attributes) 
    mock.valid? 
    mock.errors.to_hash.select { |attribute| attributes.include? attribute }.each do |error_key, error_messages| 
     error_messages.each do |error_message| 
     self.errors.add(error_key, error_message) 
     end 
    end 

    self.errors.to_hash.empty? 
    end 
end 

> my_model.valid_attributes? [:first_name, :email] # => returns true if first_name and email is valid, returns false if at least one is not valid 
> my_modal.errors.messages # => now contain errors of the previous validation 
{'first_name' => ["can't be blank"]} 
Cuestiones relacionadas