Comment mettre à jour les attributs sans validation

132

J'ai un modèle avec ses validations et j'ai découvert que je ne peux pas mettre à jour un attribut sans valider l'objet auparavant.

J'ai déjà essayé d'ajouter une on => :createsyntaxe à la fin de chaque ligne de validation, mais j'ai obtenu les mêmes résultats.

Mon modèle d'annonce a les validations suivantes:

  validates_presence_of :title
  validates_presence_of :description
  validates_presence_of :announcement_type_id

  validate :validates_publication_date
  validate :validates_start_date
  validate :validates_start_end_dates
  validate :validates_category
  validate :validates_province

  validates_length_of :title, :in => 6..255, :on => :save
  validates_length_of :subtitle, :in => 0..255, :on => :save
  validates_length_of :subtitle, :in => 0..255, :on => :save
  validates_length_of :place, :in => 0..50, :on => :save

  validates_numericality_of :vacants, :greater_than_or_equal_to => 0,  :only_integer => true
  validates_numericality_of :price, :greater_than_or_equal_to => 0,  :only_integer => true

Ma tâche de râteau fait ce qui suit:

  task :announcements_expiration => :environment do
    announcements = Announcement.expired

    announcements.each do |a|
      #Gets the user that owns the announcement
      user = User.find(a.user_id)
      puts a.title + '...'

      a.state = 'deactivated'

      if a.update_attributes(:state => a.state)
        puts 'state changed to deactivated'
      else
        a.errors.each do |e|
          puts e
        end

      end
    end

Cela lève toutes les exceptions de validation pour ce modèle, dans la sortie.

Est-ce que quelqu'un comment mettre à jour un attribut sans valider le modèle?

Brian Roisentul
la source

Réponses:

177

UTILISEZ update_attribute au lieu de update_attributes

Met à jour un seul attribut et enregistre l'enregistrement sans passer par la procédure de validation normale.

if a.update_attribute('state', a.state)

Remarque: - 'update_attribute' ne met à jour qu'un seul attribut à la fois à partir du code donné en question, je pense que cela fonctionnera pour vous.

Salil
la source
9
Vous pouvez utiliser save (false) sans validation
Dzmitry
31
update_attributeest obsolète dans Rails 4, FYI. Essayez d'utiliser a.attributes ({...}). Save (false) à la place. Ou si vous ne vous souciez pas (ou ne voulez pas) que les rappels soient exécutés, vérifiez update_column.
Joshua Pinter
27
Pour Rails 4, save(false)ne fonctionne pas, vous devez utilisersave(validate: false)
Tobias Cohen
7
@JoshPinter Hm, update_attributene semble pas être obsolète dans Rails 4.2 (il est aliasé comme update_column): api.rubyonrails.org/classes/ActiveRecord/…
Tonči D.
3
@ TončiD. Wow, vous avez absolument raison. Il semble qu'ils avaient l'intention de le déprécier dans la version 3.2 et de le supprimer dans la version 4.0, mais ont ensuite décidé de revenir sur leur décision car il n'était pas interchangeable avec update_column. Beaucoup de choses peuvent changer en deux ans! :) Merci de l'avoir signalé. Pour en savoir plus, cliquez ici: groups.google.com/forum/?hl=en&fromgroups#!topic/…
Joshua Pinter
185

Vous pouvez faire quelque chose comme:

object.attribute = value
object.save(:validate => false)
Olivier Grimard
la source
13
en fait son object.save (: validate => false)
Ken Mazaika
1
Oui. object.save (: validate => false) fonctionne pour moi. Merci beaucoup pour l'indication!
Robert Reiz
1
object.attributes = hashest un peu plus conforme à la question. Si quelqu'un se demande, il le fait update_attributes(hash)tout simplement self.attributes = hash; save.
Lloeki
1
object.save (false) est tout ce qui fonctionnera si vous utilisez Rails 2 et inférieurs
stevenspiel
C'est mieux car cela exécuterait toujours les rappels qui mettent à jour les horodatages. L'op mentionne spécifiquement éviter les validations, pas TOUS les rappels.
saneshark
79

essayez d'utiliser

@record.assign_attributes({ ... })
@record.save(validate: false)

travaille pour moi

res
la source
3
c'est la réponse valide avec Rails 4, une combinaison de tous les commentaires à la réponse actuellement acceptée.
toobulkeh
33

Vous pouvez utiliser:

a.update_column :state, a.state

Vérifiez: http://apidock.com/rails/ActiveRecord/Persistence/update_column

Met à jour un seul attribut d'un objet, sans appeler save.

William Wong Garay
la source
6
C'est la meilleure approche si vous souhaitez ignorer les validations et les rappels. Il y en a aussi update_columnssi vous souhaitez mettre à jour plusieurs attributs.
Zach Colon
7

Toutes les validations du modèle sont ignorées lorsque nous utilisons validate: false

user = User.new(....)
user.save(validate: false)
MZaragoza
la source
Exactement ce dont j'avais besoin. Merci Monsieur!
Ajunpreet Bambrah
-1

Cela ne devrait-il pas être

validates_length_of :title, :in => 6..255, :on => :create

donc cela ne fonctionne que pendant la création?

Saifis
la source
L'OP a déclaré:I already tried to add on => :create syntax at the end of each validation line, but I got the same results.
iwasrobbed le