17

If I do the following:

@user.name = "John"    
@user.url = "www.john.com"
@user.save

If I use after_save

@user.url = "www.johnseena.com"
@user.save

What will happen when I do this?

I believe it should save the value because of the 'after_save' callback.

Arslan Ali
  • 17,418
  • 8
  • 58
  • 76
SSP
  • 2,650
  • 5
  • 31
  • 49

5 Answers5

39

In my opinion, if you call save function in a after_save callback, then it will trap into a recursion unless you put a guard at the beginning. like this

class User < AR::Base
      after_save :change_url

      def change_url
          #Check some condition to skip saving
          url = "www.johnseena.com"
          save              #<======= this save will fire the after_save again
      end
end

However, apart from putting a guard, you can use update_column also

def change_url
    update_column(:url, "www.johnseena.com")
end

In this case it will not fire after_save. However, it will fire after_update. So if you have any update operation on that call back then you are in recursion again :)

Samiron
  • 5,169
  • 2
  • 28
  • 55
  • Great way to explain Thanks for your time. – SSP Oct 11 '12 at 10:18
  • 5
    NOTE: `#update_column` actually [skips callbacks](http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update_columns). – jibiel Aug 08 '17 at 14:02
7

The after_save callback will be triggered irrespective its a save or an update on that object.

Also,

update_column doesn't trigger any callbacks(ie after_update) and skips validations too. see http://apidock.com/rails/ActiveRecord/Persistence/update_column

U should specifically use after_create or after_update depending upon the operation and its timing.

after_create :send_mail
def send_x_mail
  #some mail that user has been created
end

after_update :send_y_mail
def send_y_mail
  #some data has been updated
end

after_save :update_some_date
def update_some_data
  ...
  action which doesnt update the current object else will trigger the call_back
end

Also see What is the difference between `after_create` and `after_save` and when to use which? and for callbacks see http://ar.rubyonrails.org/classes/ActiveRecord/Callbacks.html#M000059

Community
  • 1
  • 1
Prasad Surase
  • 6,486
  • 6
  • 39
  • 58
  • `after_update` and `before_update` are both exist as of rails 4.1 . You can check the complete list of available callbacks from [Rails Guide](http://guides.rubyonrails.org/active_record_callbacks.html#available-callbacks) – Steven Yue Nov 12 '14 at 18:29
4

If you modify anything int the after_save it won't be saved, as the save is already taken place. The only chance to intervene is to rollback the whole transaction. If you add another save in the after_save, then it will be an infinite loop.

Arslan Ali
  • 17,418
  • 8
  • 58
  • 76
Matzi
  • 13,770
  • 4
  • 33
  • 50
1

Instead of performing two queries to the database and worrying about recursion, you may want to consider just modifying the data payload before it goes to the server.

class User < AR::Base
      before_save :change_url

      def change_url
          url = "www.johnseena.com"
      end
end
ProLoser
  • 4,616
  • 2
  • 16
  • 23
0

Many thanks to everyone who helped me out here. Here is the solution which solved my problem. I modified by order model to the following:

class Order < ActiveRecord::Base

  has_and_belongs_to_many :users

  validates :item, presence: true

  def add_order(username, order)
    user = User.where(username: username).first
    if !user.nil?
      user.orders.create(item: order.item)
    end
  end

  def remove_order(order)
  end

end
CodeYogi
  • 1,369
  • 3
  • 12
  • 14