Ruby-on-rails 保存对象时 after_save 如何工作

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12835029/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 20:51:33  来源:igfitidea点击:

How does after_save work when saving an object

ruby-on-railsrubyruby-on-rails-3ruby-on-rails-3.1ruby-on-rails-3.2

提问by SSP

If I do the following:

如果我执行以下操作:

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

If I use after_save

如果我使用 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.

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

回答by Samiron

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

在我看来,如果您saveafter_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

However, apart from putting a guard, you can use update_columnalso

然而,除了把一个后卫,你可以使用update_column

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 :)

在这种情况下它不会触发after_save。但是,它会触发after_update。因此,如果您对该回调有任何更新操作,那么您将再次递归:)

回答by prasad.surase

The after_savecallback will be triggered irrespective its a saveor an updateon that object.

after_save的回调函数会被触发,不论它是一个保存更新该对象上。

Also,

还,

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

update_column不会触发任何回调(即 after_update)并跳过验证。见http://apidock.com/rails/ActiveRecord/Persistence/update_column

U should specifically use after_createor after_updatedepending upon the operation and its timing.

你应该根据操作及其时间专门使用after_createafter_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

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

另请参阅“after_create”和“after_save”之间有什么区别以及何时使用哪个?和回调见http://ar.rubyonrails.org/classes/ActiveRecord/Callbacks.html#M000059

回答by Matzi

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

如果您修改任何 int 内容,after_save它将不会被保存,因为save已经发生了。唯一的干预机会是回滚整个事务。如果添加另一个saveafter_save,那么这将是一个无限循环。

回答by ProLoser

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

回答by CodeYogi

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