如何更新after_save中的属性而不会导致rails 2.3中的递归?

问题描述 投票:12回答:5

我有一个模型,附有Paperclip的视频。保存后,我使用保存的视频生成缩略图。我需要在每次保存后执行此操作,即使尚未上传新视频,因为用户可以更改捕获缩略图的时间。

我目前正在使用after_post_process来执行此操作,但它只会在上传文件时生成缩略图(这是回调,它是Paperclip的一部分)。

理想情况下我会使用这样的after_save回调:

after_save :save_thumbnail
def save_thumbnail
  #generate thumbnail...
  self.update_attributes(
    :thumbnail_file_name => File.basename(thumb), 
    :thumbnail_content_type => 'image/jpeg'
  )
end

不幸的是,update_attributes调用save,然后调用before_save回调导致无限循环。是否有一种简单的方法来规避这种行为?

ruby-on-rails callback save ruby-on-rails-2
5个回答
9
投票

您可以将其包装在条件中,例如:

def save_thumbnail
  if File.basename(thumb) != thumbnail_file_name
    self.update_attributes(
      :thumbnail_file_name => File.basename(thumb), 
      :thumbnail_content_type => 'image/jpeg'
    )
  end
end

这样它只会运行一次。


9
投票

在qailsxswpoi回调中的任何update_attribute将导致Rails3 +中的递归。应该做的是:

after_save

以下是一些关于它的文档:after_save :updater! # Awesome Ruby code # ... # ... private def updater! self.update_column(:column_name, new_value) # This will skip validation gracefully. end


8
投票

Rails 2:

https://guides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks

Rails 3:

Model.send(:create_without_callbacks)
Model.send(:update_without_callbacks)

看到这个问题:

Vote.skip_callback(:save, :after, :add_points_to_user)


2
投票

您可以(并且应该)检查您是否确实需要更新缩略图:

How to skip ActiveRecord callbacks?

在这里,您可以阅读更多关于'脏'属性:after_save :save_thumbnail def save_thumbnail if capture_time_changed? #assuming capture_time contains time when the thumbnail has to be captured #generate thumbnail... self.update_attributes( :thumbnail_file_name => File.basename(thumb), :thumbnail_content_type => 'image/jpeg' ) end end

虽然我不确定它是否仍然可以看到after_save中的属性更改。您可以使用成员变量来指示更改,以防万一。


0
投票

您可以将其作为http://apidock.com/rails/ActiveRecord/Dirty运行。

验证后,更新缩略图,然后继续保存,但只需使用分配方法

before_save

因为那不会调用save,所以你不会递归,但是在方法退出后会立即保存。

这样的东西应该有用,除非你有明确的理由在保存后需要它。

由于您不是更新单独的对象,而是更新同一个对象,因此这也将为您节省数据库调用。这就是我如何做时间戳和类似的事情。

© www.soinside.com 2019 - 2024. All rights reserved.