Skip to main content

Active Record

The activerecord plugin adds Active Record integration to the attachment interface. It is built on top of the model plugin.

Shrine.plugin :activerecord

Attachment

Including a Shrine::Attachment module into an ActiveRecord::Base subclass will:

class Photo < ActiveRecord::Base # has `image_data` column  include ImageUploader::Attachment(:image) # adds methods, callbacks & validations end
photo = Photo.new  photo.image = file # cache attachment  photo.image #=> #<Shrine::UploadedFile id="bc2e13.jpg" storage=:cache ...> photo.image_data #=> '{"id":"bc2e13.jpg","storage":"cache","metadata":{...}}'  photo.save # persist, promote attachment, then persist again  photo.image #=> #<Shrine::UploadedFile id="397eca.jpg" storage=:store ...> photo.image_data #=> '{"id":"397eca.jpg","storage":"store","metadata":{...}}'  photo.destroy # delete attachment  photo.image.exists? #=> false

Callbacks

After Save

After a record is saved and the transaction is committed, Attacher#finalize is called, which promotes cached file to permanent storage and deletes previous file if any.

photo = Photo.new  photo.image = file photo.image.storage_key #=> :cache  photo.save photo.image.storage_key #=> :store

After Destroy

After a record is destroyed and the transaction is committed, Attacher#destroy_attached method is called, which deletes stored attached file if any.

photo = Photo.find(photo_id) photo.image #=> #<Shrine::UploadedFile> photo.image.exists? #=> true  photo.destroy photo.image.exists? #=> false

Caveats

Active Record currently has a bug with transaction callbacks, so if you have any "after commit" callbacks, make sure to include Shrine's attachment module after they have all been defined.

Overriding callbacks

You can override any of the following attacher methods to modify callback behaviour:

  • Attacher#activerecord_before_save
  • Attacher#activerecord_after_save
  • Attacher#activerecord_after_destroy
class Shrine::Attacher  def activerecord_after_save  super  # ...  end end

Skipping Callbacks

If you don't want the attachment module to add any callbacks to your model, you can set :callbacks to false:

plugin :activerecord, callbacks: false

Validations

If you're using the validation plugin, the attachment module will automatically merge attacher errors with model errors.

class ImageUploader < Shrine  plugin :validation_helpers   Attacher.validate do  validate_max_size 10 * 1024 * 1024  end end
photo = Photo.new photo.image = file photo.valid? photo.errors #=> { image: ["size must not be greater than 10.0 MB"] }

Attachment Presence

If you want to validate presence of the attachment, you can use Active Record's presence validator:

class Photo < ActiveRecord::Base  include ImageUploader::Attachment(:image)   validates_presence_of :image end

I18n

If you want Active Record to translate attacher error messages, you can use symbols or arrays of symbols and options for validation errors:

class ImageUploader < Shrine  plugin :validation_helpers   Attacher.validate do  validate_max_size 10 * 1024 * 1024, message: -> (max) { [:too_large, max: max] }  validate_mime_type %w[image/jpeg image/png], message: :not_image  end end
en:  activerecord:  errors:  models:  photo:  attributes:  image:  max_size: "must not be larger than %{max_size} bytes"  not_image: "must be a common image format"

Skipping Validations

If don't want the attachment module to merge file validations errors into model errors, you can set :validations to false:

plugin :activerecord, validations: false

Attacher

You can also use Shrine::Attacher directly (with or without the Shrine::Attachment module):

class Photo < ActiveRecord::Base # has `image_data` column end
photo = Photo.new attacher = ImageUploader::Attacher.from_model(photo, :image)  attacher.assign(file) # cache  attacher.file #=> #<Shrine::UploadedFile id="bc2e13.jpg" storage=:cache ...> photo.image_data #=> '{"id":"bc2e13.jpg","storage":"cache","metadata":{...}}'  photo.save # persist attacher.finalize # promote photo.save # persist  attacher.file #=> #<Shrine::UploadedFile id="397eca.jpg" storage=:store ...> photo.image_data #=> '{"id":"397eca.jpg","storage":"store","metadata":{...}}'

Persistence

The following persistence methods are added to Shrine::Attacher:

MethodDescription
Attacher#atomic_promotecalls Attacher#promote and persists if the attachment hasn't changed
Attacher#atomic_persistsaves changes if the attachment hasn't changed
Attacher#persistsaves any changes to the underlying record

See persistence docs for more details.