class Shrine::Plugins::KithePromotionCallbacks
We want ActiveSupport-style callbacks around “promotion” – the shrine process of finalizing a file by moving it from 'cache' storage to 'store' storage.
We want to suport after_promotion hooks, and before_promotion hooks, the before_promotion hooks should be able to cancel promotion. (A convenient way to do validation even with backgrounding promotion, although you'd want to record the validation fail somewhere)
For now, the actual hooks are registered in the `Asset` activerecord model. This works because our Asset model only has ONE shrine attachment, it is backwards compatible with kithe 1. It might make more sense to have the callbacks on the Uploader itself, in the future though.
We want to be able to register these callbacks, and have them invoked regardless of how promotion happens – inline; in a background job; or even explicitly calling Asset#promote
## Weird implementation
It's a bit hard to get this to happen in shrine architecture. We end up needing to assume activerecord and wrap the activerecord_after_save method (for inline promotion). And then also overwrite atomic_promote to get background promotion and other cases.
Because getting this right required some shuffling around of where the wrapping happened, it was convenient and avoided confusion to isolate wrapping in a class method that can be used anywhere, and only depends on args passed in, no implicit state anywhere.
Public Class Methods
# File lib/shrine/plugins/kithe_promotion_callbacks.rb, line 27 def self.load_dependencies(uploader, *) uploader.plugin :kithe_promotion_directives end
promotion logic differs somewhat in different modes of use (bg or inline promotion), so we extract the wrapping logic here. Exactly what the logic wrapped is can differ.
Kithe::PromotionCallbacks.with_promotion_callbacks(record) do promotion_logic # sometimes `super` end
# File lib/shrine/plugins/kithe_promotion_callbacks.rb, line 39 def self.with_promotion_callbacks(model) # If callbacks haven't been skipped, and we have a model that implements # callbacks, wrap yield in callbacks. # # Otherwise, just do it. if ( !model.file_attacher.promotion_directives["skip_callbacks"] && model && model.class.respond_to?(:_promotion_callbacks) ) model.run_callbacks(:promotion) do yield end else yield end end