Como atualizar atributos sem validação

132

Eu tenho um modelo com suas validações e descobri que não posso atualizar um atributo sem validar o objeto antes.

Eu já tentei adicionar on => :createsintaxe no final de cada linha de validação, mas obtive os mesmos resultados.

Meu modelo de anúncio tem as seguintes validações:

  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

Minha tarefa de rake faz o seguinte:

  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

Isso lança todas as exceções de validação para esse modelo, na saída.

Alguém como atualizar um atributo sem validar o modelo?

Brian Roisentul
fonte

Respostas:

177

USE update_attribute em vez de update_attributes

Atualiza um único atributo e salva o registro sem passar pelo procedimento de validação normal.

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

Nota: - 'update_attribute' atualiza apenas um atributo de cada vez do código fornecido em questão, acho que funcionará para você.

Salil
fonte
9
Você pode usar save (false) sem validação
Dzmitry
31
update_attributefoi descontinuado no Rails 4, FYI. Tente usar a.attributes ({...}). Save (false). Ou se você não se importa (ou deseja) que retornos de chamada sejam executados, faça o checkout update_column.
Joshua Pinter
27
Para Rails 4, save(false)não funciona, você deve usarsave(validate: false)
Tobias Cohen
7
@JoshPinter Hm, update_attributenão parece ser preterido em trilhos 4.2 (que é alias como update_column): api.rubyonrails.org/classes/ActiveRecord/...
Tonči D.
3
@ TončiD. Uau, você está absolutamente correto. Parece que eles pretendiam descontinuá-lo no 3.2 e removê-lo no 4.0, mas decidiram reverter sua decisão, pois não era intercambiável update_column. Muita coisa pode mudar em dois anos! :) Obrigado por apontar isso. Leia mais sobre o assunto aqui: groups.google.com/forum/?hl=pt_BR&fromgroups#!topic/…
Joshua Pinter
185

Você pode fazer algo como:

object.attribute = value
object.save(:validate => false)
Olivier Grimard
fonte
13
na verdade, a sua object.save (: validate => false)
Ken Mazaika
1
Sim. object.save (: validate => false) funciona para mim. Muito obrigado pela dica!
Robert Reiz
1
object.attributes = hashestá um pouco mais alinhado com a pergunta. Se alguém se pergunta, update_attributes(hash)ele próprio simplesmente faz self.attributes = hash; save.
Lloeki 29/04
1
object.save (false) é tudo o que vai funcionar se usando Rails 2 e abaixo
stevenspiel
Isso é melhor porque ainda executaria os retornos de chamada que atualizam os carimbos de data / hora. O op menciona especificamente evitar validações, não TODOS os retornos de chamada.
precisa saber é
79

tente usar

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

funciona para mim

res
fonte
3
esta é a resposta válida no Rails 4, uma combinação de todos os comentários para a resposta atualmente aceita.
toobulkeh
33

Você pode usar:

a.update_column :state, a.state

Verifique: http://apidock.com/rails/ActiveRecord/Persistence/update_column

Atualiza um único atributo de um objeto, sem chamar save.

William Wong Garay
fonte
6
Essa é a melhor abordagem se você quiser pular validações e retornos de chamada. Também existe update_columnsse você estiver procurando atualizar vários atributos.
Zach Colon
7

Toda a validação do modelo é ignorada quando usamos validate: false

user = User.new(....)
user.save(validate: false)
MZaragoza
fonte
Exatamente o que eu precisava. Obrigado, gentil senhor!
você precisa saber é o seguinte
-1

Isso não deveria ser

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

então só funciona durante a criação?

Saifis
fonte
O OP disse:I already tried to add on => :create syntax at the end of each validation line, but I got the same results.
iwasrobbed