165

I've got a model with its validations, and I found out that I can't update an attribute without validating the object before.

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

My announcement model have the following validations:

  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

My rake task does the following:

  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

This throws all the validation exceptions for that model, in the output.

Does anybody how to update an attribute without validating the model?

Larry K
  • 47,808
  • 15
  • 87
  • 140
Brian Roisentul
  • 4,590
  • 8
  • 53
  • 81

6 Answers6

241

You can do something like:

object.attribute = value
object.save(validate: false)
Joshua Pinter
  • 45,245
  • 23
  • 243
  • 245
Olivier Grimard
  • 2,783
  • 1
  • 16
  • 8
  • 13
    actually its object.save(:validate => false) – Ken Mazaika Feb 29 '12 at 16:34
  • 3
    `object.attributes = hash` is a little more in line with the question. If anyone wonders, `update_attributes(hash)` itself merely does `self.attributes = hash; save`. – Lloeki Apr 29 '14 at 08:30
  • 1
    object.save(false) is all that will work if using Rails 2 and below – stevenspiel May 15 '14 at 18:51
  • 3
    This is better because it would still execute the callbacks that update timestamps. The op specifically mentions avoiding validations, not ALL callbacks. – saneshark Feb 05 '15 at 18:24
  • 4
    By doing this, it is also much clearer to the next developer that the validations are explicitly not wanted – ChrisW Sep 11 '18 at 09:48
  • You can also use `.tap` if you want to do it on 1 line of code: `object.tap { |o| o.attribute = value }.save(validate: false)` – stwr667 Nov 12 '20 at 07:45
  • Just curious, how can this be used to skip only a particular validation in the case when you dont want to skip everything? – seunadex Jun 06 '22 at 09:03
213

USE update_attribute instead of update_attributes

Updates a single attribute and saves the record without going through the normal validation procedure.

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

Note:- 'update_attribute' update only one attribute at a time from the code given in question i think it will work for you.

Nathan
  • 1,762
  • 1
  • 20
  • 30
Salil
  • 46,566
  • 21
  • 122
  • 156
  • 9
    You can use save(false) without validation – Dzmitry Jan 16 '12 at 13:06
  • 1
    Hmm, but is there a way that still parses out params[:instance] like update_attributes does? – Dogweather Aug 23 '12 at 02:03
  • 34
    `update_attribute` is deprecated in Rails 4, FYI. Try using a.attributes({ ... }).save(false) instead. Or if you don't care (or want) callbacks to be run, checkout `update_column`. – Joshua Pinter Dec 10 '12 at 02:45
  • 33
    For Rails 4, `save(false)` doesn't work, you must use `save(validate: false)` – Tobias Cohen Jan 21 '14 at 06:00
  • 10
    @JoshPinter Hm, `update_attribute` doesn't seem to be deprecated in Rails 4.2 (it is aliased as `update_column`): http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update_attribute – Tonči D. Mar 18 '15 at 11:27
  • 4
    @TončiD. Wow, you are absolutely correct. It looks like they intended to deprecate it in 3.2 and remove it in 4.0 but then decided to reverse their decision since it was not interchangeable with `update_column`. A lot can change in two years! :) Thanks for pointing it out. Read more about it here: https://groups.google.com/forum/?hl=en&fromgroups#!topic/rubyonrails-core/BWPUTK7WvYA – Joshua Pinter Mar 19 '15 at 14:18
  • `update_attributes` was deprecated in Rails 6.0 and removed in Rails 6.1. – Arenzel Jul 07 '22 at 13:44
102

try using

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

works for me

Dorian
  • 22,759
  • 8
  • 120
  • 116
res
  • 1,205
  • 1
  • 8
  • 21
  • 3
    this is the valid answer with Rails 4, a combination of all the comments to the currently accepted answer. – toobulkeh Jun 09 '15 at 19:20
  • `@record.tap { |r| r.assign_attributes({ ... }) }.save(validate: false)` does it on 1 line of code if you prefer. – stwr667 Nov 12 '20 at 07:47
48

Yo can use:

a.update_column :state, a.state

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

Updates a single attribute of an object, without calling save.

William Wong Garay
  • 1,921
  • 18
  • 14
  • 9
    This is the best approach if you want to skip both validations and callbacks. There is also `update_columns` if you're looking to update multiple attributes. – Zach Colon Feb 08 '17 at 00:40
10

All the validation from model are skipped when we use validate: false

user = User.new(....)
user.save(validate: false)
MZaragoza
  • 10,108
  • 9
  • 71
  • 116
0

Shouldn't that be

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

so it only works during create?

Saifis
  • 2,197
  • 1
  • 22
  • 36
  • The OP said: `I already tried to add on => :create syntax at the end of each validation line, but I got the same results.` – iwasrobbed Apr 29 '11 at 19:01