Как работает after_save при сохранении объекта

Если я делаю следующее:

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

Если я использую after_save

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

Что произойдет, когда я это сделаю?

Я считаю, что он должен сохранить значение из-за обратного вызова 'after_save'.

Ответ 1

На мой взгляд, если вы вызываете функцию save в обратном вызове after_save, тогда она будет ловушка в рекурсию, если вы не установите охрану в начале. как это

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

Однако, помимо установки охраны, вы можете использовать update_column также

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

В этом случае он не срабатывает after_save. Однако он срабатывает after_update. Поэтому, если у вас есть операция обновления для этого вызова, вы снова находитесь в рекурсии:)

Ответ 2

Обратный вызов after_save будет запускаться независимо от сохранения или обновления на этом объекте.

Кроме того,

update_column не вызывает никаких обратных вызовов (т.е. after_update) и также пропускает проверки. см. http://apidock.com/rails/ActiveRecord/Persistence/update_column

U должен использовать after_create или after_update, в зависимости от операции и времени.

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

Также см. В чем разница между` after_create` и `after_save` и когда использовать, что? и для обратных вызовов см. http://ar.rubyonrails.org/classes/ActiveRecord/Callbacks.html#M000059

Ответ 3

Если вы измените что-либо int after_save, оно не будет сохранено, так как save уже выполнено. Единственный шанс вмешаться - это откат всей транзакции. Если вы добавите еще save в after_save, то это будет бесконечный цикл.

Ответ 4

Вместо того, чтобы выполнять две запросы к базе данных и беспокоиться о рекурсии, вы можете захотеть просто модифицировать полезную нагрузку данных до ее выхода на сервер.

class User < AR::Base
      before_save :change_url

      def change_url
          url = "www.johnseena.com"
      end
end

Ответ 5

Большое спасибо всем, кто помог мне здесь. Вот решение, которое решило мою проблему. Я изменил модель заказа на следующее:

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