保存对象时after_save如何工作

时间:2012-10-11 08:11:12

标签: ruby-on-rails ruby ruby-on-rails-3 ruby-on-rails-3.1 ruby-on-rails-3.2

如果我执行以下操作:

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

如果我使用after_save

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

当我这样做会发生什么?

我认为它应该保存值,因为'after_save'回调。

5 个答案:

答案 0 :(得分:32)

在我看来,如果你在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。因此,如果您对该回调有任何更新操作,那么您再次进行递归:)

答案 1 :(得分:6)

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

另见What is the difference between `after_create` and `after_save` and when to use which?,有关回调,请参阅http://ar.rubyonrails.org/classes/ActiveRecord/Callbacks.html#M000059

答案 2 :(得分:4)

如果您修改after_save中的任何内容,则不会保存,因为save已经发生。干预的唯一机会是回滚整个交易。如果您在save中添加另一个after_save,那么它将是一个无限循环。

答案 3 :(得分:1)

您可能只想考虑在数据有效负载进入服务器之前修改数据有效负载,而不是对数据库执行两次查询并担心递归。

class User < AR::Base
      before_save :change_url

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

答案 4 :(得分:0)

非常感谢帮助我的所有人。这是解决我的问题的解决方案。我按订单模型修改了以下内容:

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