Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I update attributes in after_save without causing a recursion in rails 2.3?

I've got a model which has a video attached with Paperclip. After it saves I use the saved video to generate a thumbnail. I need to do this after every save, even when a new video hasn't been uploaded, because the user can change the time where the thumbnail is captured.

I am currently using after_post_process to do this, but it will only generate the thumbnail when uploading a file (this is a callback which is part of Paperclip).

I would ideally use an after_save callback like this:

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

Unfortunately update_attributes calls save, which then calls the before_save callback causing an infinite loop. Is there a simple way to circumvent this behaviour?

like image 441
peterjwest Avatar asked Jul 13 '11 15:07

peterjwest


3 Answers

Any update_attribute in an after_save callback will cause recursion, in Rails3+. What should be done is:

after_save :updater!
# Awesome Ruby code
# ...
# ...

private

  def updater!
    self.update_column(:column_name, new_value) # This will skip validation gracefully.
  end

Here is some documentation about it: https://guides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks

like image 130
zakelfassi Avatar answered Nov 02 '22 00:11

zakelfassi


You could wrap it in a conditional, something like:

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

That way it would only run once.

like image 24
Dylan Markow Avatar answered Nov 02 '22 00:11

Dylan Markow


Rails 2:

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

Rails 3:

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

See this question:

How to skip ActiveRecord callbacks?

like image 8
thenengah Avatar answered Nov 02 '22 00:11

thenengah