Persistence | Shrine (original) (raw)
This is an internal plugin that provides uniform persistence interface across different persistence plugins (e.g. activerecord,sequel).
For these activerecord and sequel, atomic persistence is implemented in terms of database locks, eg "SELECT... FOR UPDATE". For more discussion of concurrency challenges, see the atomic_helpers documentation.
If you're promoting cached file to permanent storageasynchronously, and want to handle the possibility of attachment changing during promotion, you can use Attacher#atomic_promote
:
# in your controller
attacher.attach_cached(io)
attacher.cached? #=> true
# in a background job
attacher.atomic_promote # promotes cached file and persists
attacher.stored? #=> true
After the cached file is uploaded to permanent storage, the record is reloaded in order to check whether the attachment hasn't changed, and if it hasn't the attachment is persisted. If the attachment has changed,Shrine::AttachmentChanged
exception is raised.
If you want to execute code after the attachment change check but before persistence, you can pass a block:
attacher.atomic_promote do |reloaded_attacher|
# run code after attachment change check but before persistence
end
You can pass :reload
and :persist
options to change how the record is reloaded and pesisted. See the atomic_helpers plugin docs for more details.
Any other options are forwarded to Attacher#promote
:
attacher.atomic_promote(metadata: true) # re-extract metadata
Atomic persistence
If you're updating something based on the attached fileasynchronously, you might want to handle the possibility of the attachment changing in the meanwhile. You can do that withAttacher#atomic_persist
:
# in a background job
attacher.refresh_metadata! # refresh_metadata plugin
attacher.atomic_persist # persists attachment data
The record is first reloaded in order to check whether the attachment hasn't changed, and if it hasn't the attachment is persisted. If the attachment has changed, Shrine::AttachmentChanged
exception is raised.
If you want to execute code after the attachment change check but before persistence, you can pass a block. For instance, one way to allow concurrent changes to metadata, perhaps in different background workers, without overwriting each other might be:
attacher.atomic_persist do |reloaded_attacher|
# run code after attachment change check but before persistence
attacher.file.metadata.merge!(reloaded_attacher.file.metadata)
attacher.file.metadata["some_key"] = "changed_value"
end
You can pass :reload
and :persist
options to change how the record is reloaded and pesisted. See the atomic_helpers plugin docs for more details.
Simple Persistence
To simply save attachment changes to the underlying record, useAttacher#persist
:
attacher.attach(io)
attacher.persist # saves the underlying record