VivekVarade123
VivekVarade123

Reputation: 3684

rails after_save infinite loop

I have a model which stores the details for retail outlets.

In Outlet model I have a before filter

after_save :is_outlet_verified

def is_outlet_verified
    if self.latitude.present? && self.longitude.present?
      self.update_attributes(:is_verified => true)
    else
      self.update_attributes(:is_verified => false)
    end
  end

I want to set is_verified field to true if outlet is geocoded. However when is_outlet_verified is successfully executed, it triggers after_save callback which again triggers is_outlet_verified.

Upvotes: 6

Views: 7529

Answers (4)

Karthick Nagarajan
Karthick Nagarajan

Reputation: 1345

I recently I faced this issue and I solved to use this :)

update_columns(attributes) public

Updates the attributes directly in the database issuing an UPDATE SQL statement and sets them in the receiver:

user.update_columns(last_request_at: Time.current)

This is the fastest way to update attributes because it goes straight to the database but take into account that in consequence the regular update procedures are totally bypassed. In particular:

Validations are skipped.

Callbacks are skipped.

updated_at/updated_on are not updated.

This method raises an +ActiveRecord::ActiveRecordError+ when called on new objects, or when at least one of the attributes is marked as readonly.

Upvotes: 2

sevenseacat
sevenseacat

Reputation: 25029

Ideally you would do something like this in a before_save callback, not after_save - just set the is_verified attribute and then just let the save take place as normal.

If you really need to do this, you can use update_column instead of update_attribute, which will skip all callbacks.

One caveat to note - if a before_save callback returns false, then the save will not go ahead.

Upvotes: 19

Richard Peck
Richard Peck

Reputation: 76774

.update_attributes invokes the .save method, so calling it after_save creates an infinite loop

I'd do it before_save, like this:

before_save :is_outlet_verified

  def is_outlet_verified
    if self.latitude.present? && self.longitude.present?
      self.is_verified = true
    else
      self.is_verified = false
    end
  end

Upvotes: 5

Rajarshi Das
Rajarshi Das

Reputation: 12320

you can use after_create instead of after_save to avoid infinte loop occurred by update_attributes

Upvotes: 2

Related Questions