2011-08-23 12 views
5

Ho il seguente nel mio modello utenteconvalidare e aggiornare attributo singola scaglia

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? } 

in uno dei miei controllori, voglio solo aggiornare e validare il campo avatar senza aggiornare e validare email.

Come posso fare questo?

per esempio (questo non funzionerà)

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

Ho anche provato con update_attribute('avatar', params[:user][:avatar]), ma sarebbe saltare le convalide per avatar campo pure.

+1

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

+0

no, penso 'mock .valid? 'convalida tutto. Sto cercando di convalidare solo un attributo. – Madhusudhan

risposta

13

È possibile validate the attribute by hand e utilizzare update_attribute, quello skips validation. Se si aggiunge 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 

e quindi aggiornare l'attributo di questa convenzione:

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

Si dovrebbe ottenere il vostro singolo attributo aggiornato mentre solo (manualmente) convalidare tale attributo.

Se si guarda come funziona lo valid_attribute? di Milano Novota, si vedrà che esegue le convalide e quindi controlla se lo specifico attr ha avuto problemi; non importa se nessuna delle altre validazioni fallisce come valid_attribute? guarda solo i fallimenti di validazione per l'attributo che ti interessa.

Se hai intenzione di fare un sacco di questa roba allora potresti aggiungi un metodo all'utente:

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

e utilizzalo per aggiornare il tuo singolo attributo.

+0

questo controllerebbe anche per le convalide e-mail, solo non avatar. – Madhusudhan

+0

@Madhusudhan: puoi impostare la validazione a mano e usare 'update_attribute'. Si prega di consultare il mio aggiornamento. –

+0

yup che ha aiutato! Grazie! – Madhusudhan

1

Hai provato a mettere una condizione sul validates_presence_of :email?

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

Le opzioni di configurazione:

se - specifica un metodo, proc o una stringa di chiamare per determinare se dovesse verificarsi la validazione (ad esempio: se =>: allow_validation, oppure: if => Proc.new {| user | user.signup_step> 2}). Il metodo, proc o stringa deve restituire o valutare un valore vero o falso.

a meno che - specifica un metodo, proc o una stringa di chiamare per determinare se la convalida non dovrebbe verificarsi (ad esempio: a meno =>: skip_validation, oppure: a meno => {Proc.new | user | user.signup_step < = 2 }). Il metodo, proc o stringa deve restituire o valutare un valore vero o falso.

1

Suppongo che sia necessario, perché si dispone di un wizard multi-step, in cui si carica l'avatar per la prima volta e l'e-mail viene compilata in un secondo momento.

Per quanto ne so, con le convalide così come sono, non vedo alcuna soluzione funzionante. O convalidi tutti o aggiorni l'avatar senza convalida.Se si trattasse di un semplice attributo, è possibile verificare se il nuovo valore supera la convalida separatamente, quindi aggiornare il modello senza convalide (ad esempio utilizzando update_attribute).

posso suggerire due possibili approcci alternativi:

  • o si assicurarsi che l'e-mail è sempre entrato prima, che a mio avviso non è una cattiva soluzione. E poi, con ogni salvataggio, la convalida è soddisfatta.
  • in caso contrario, modificare la convalida. Perché dovresti dichiarare una convalida su un modello, se nel database ci sono record che non soddisfano la validazione? Questo è molto contro-intuitivo.

Quindi mi sento di proporre qualcosa di simile:

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 

Spero che questo aiuti.

+0

errors.add (: email, "Email è richiesta") genera error = "Email Email è richiesta". Modifica "L'e-mail è richiesta" per "è richiesto" –

6

Una condizione?

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

Ecco la mia soluzione. Mantiene lo stesso comportamento di .valid? Metodo, la strega restituisce true o false e aggiunge errori sul modello in cui è stato chiamato.

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"]} 
Problemi correlati