Persistence
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.
Atomic promotion
If you're promoting cached file to permanent storage
asynchronously, 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 file
asynchronously, you might want to handle the possibility of
the attachment changing in the meanwhile. You can do that with
Attacher#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, use
Attacher#persist
:
attacher.attach(io)
attacher.persist # saves the underlying record