Как обновить атрибуты после сохранения, не вызывая рекурсии в rails 2.3?
У меня есть модель, к которой прикреплено видео с скрепки. После сохранения я использую сохраненное видео для создания миниатюры. Мне нужно делать это после каждого сохранения, даже если новое видео не было загружено, потому что пользователь может изменить время захвата миниатюры.
в настоящее время я использую after_post_process для этого, но он будет генерировать эскиз только при загрузке файла (это обратный вызов, который является частью скрепки).
I идеально использовать обратный вызов 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, вызывающий бесконечный цикл. Есть ли простой способ обойти это поведение?
5 ответов
вы можете обернуть его в условное, что-то вроде:
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
таким образом, он будет работать только один раз.
рельсы 2:
Model.send(:create_without_callbacks)
Model.send(:update_without_callbacks)
рельсы 3:
Vote.skip_callback(:save, :after, :add_points_to_user)
см. Этот вопрос:
любой update_attribute
на after_save
обратный вызов вызовет рекурсию, в Rails3+.
Что следует сделать:
after_save :updater!
# Awesome Ruby code
# ...
# ...
private
def updater!
self.update_column(:column_name, new_value) # This will skip validation gracefully.
end
вы можете (и должны) проверить, действительно ли вам нужно обновить миниатюру:
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
здесь вы можете узнать больше о "грязных" атрибутах:http://apidock.com/rails/ActiveRecord/Dirty
хотя я не уверен, что он все еще может видеть изменения атрибута в after_save. Вы можете использовать переменную-член для указания изменений, если она не может.
вы можете запустить его как before_save
вместо.
после проверки обновите миниатюру, затем пусть она будет сохранена, но просто используйте методы назначения
before_save :save_thumbnail
def save_thumbnail
self.thumbnail_file_name = File.basename(thumb),
self.thumbnail_content_type = 'image/jpeg'
end
поскольку это не вызовет save, вы не будете рекурсировать, но он будет немедленно сохранен после выхода метода.
что-то вроде этого должно работать, если нет явной причины, по которой вам это нужно после сохранения.
поскольку вы не обновляете отдельный объект, но то же самое, это также сэкономит вам вызов базы данных. Вот как я делаю отметки времени и тому подобное.