Skip to content
Permalink
 
 
Cannot retrieve contributors at this time
# frozen_string_literal: true
require "active_record"
class Shrine
module Plugins
# Documentation can be found on https://shrinerb.com/docs/plugins/activerecord
module Activerecord
def self.load_dependencies(uploader, **)
uploader.plugin :model
uploader.plugin :_persistence, plugin: self
end
def self.configure(uploader, **opts)
uploader.opts[:activerecord] ||= { callbacks: true, validations: true }
uploader.opts[:activerecord].merge!(opts)
end
module AttachmentMethods
def included(model)
super
return unless model < ::ActiveRecord::Base
name = @name
if shrine_class.opts[:activerecord][:validations]
model.validate do
send(:"#{name}_attacher").send(:activerecord_validate)
end
end
if shrine_class.opts[:activerecord][:callbacks]
model.before_save do
if send(:"#{name}_attacher").changed?
send(:"#{name}_attacher").send(:activerecord_before_save)
end
end
[:create, :update].each do |action|
model.after_commit on: action do
if send(:"#{name}_attacher").changed?
send(:"#{name}_attacher").send(:activerecord_after_save)
end
end
end
model.after_commit on: :destroy do
if send(:"#{name}_attacher").attached?
send(:"#{name}_attacher").send(:activerecord_after_destroy)
end
end
end
# reload the attacher on record reload
define_method :reload do |*args|
result = super(*args)
send(:"#{name}_attacher").reload if instance_variable_defined?(:"@#{name}_attacher")
result
end
end
end
# The _persistence plugin uses #activerecord_persist,
# #activerecord_reload and #activerecord? to implement the following
# methods:
#
# * Attacher#persist
# * Attacher#atomic_persist
# * Attacher#atomic_promote
module AttacherMethods
private
# Adds file validation errors to the model. Called on model validation.
def activerecord_validate
return unless respond_to?(:errors)
errors.each do |(type, options)|
record.errors.add(name, type, **options.to_h)
end
end
# Calls Attacher#save. Called before model save.
def activerecord_before_save
save
end
# Finalizes attachment and persists changes. Called after model save.
def activerecord_after_save
finalize
persist
end
# Deletes attached files. Called after model destroy.
def activerecord_after_destroy
destroy_attached
end
# Saves changes to the model instance, skipping validations. Used by
# the _persistence plugin.
def activerecord_persist
record.save(validate: false)
end
# Locks the database row and yields the reloaded record. Used by the
# _persistence plugin.
def activerecord_reload
record.transaction { yield record.clone.reload(lock: true) }
end
# Returns true if the data attribute represents a JSON or JSONB column.
# Used by the _persistence plugin to determine whether serialization
# should be skipped.
def activerecord_hash_attribute?
column = record.class.columns_hash[attribute.to_s]
column && [:json, :jsonb].include?(column.type)
end
# Returns whether the record is an ActiveRecord model. Used by the
# _persistence plugin.
def activerecord?
record.is_a?(::ActiveRecord::Base)
end
end
end
register_plugin(:activerecord, Activerecord)
end
end