---
title: Shrine 3.9.0
---

## New features

* `Shrine.find_storage` now raises `Shrine::MissingStorage` (a subclass of `Shrine::Error`) when the storage isn't registered, instead of a generic `Shrine::Error`. This is useful with the `dynamic_storage` plugin, where the resolver might fail to find its dependencies (e.g. a deleted DB record), and lets you rescue that case separately from other errors.

  ```rb
  begin
    Shrine.find_storage(:store)
  rescue Shrine::MissingStorage
    # handle missing storage specifically
  end
  ```

* The `url_options` and `upload_options` plugins now accept a `Regexp` in place of a storage key. This is useful when storage keys are generated dynamically (e.g. via the `dynamic_storage` plugin), since it's not possible to list every storage key upfront. An exact storage key match always takes precedence over a `Regexp` match.

  ```rb
  plugin :url_options, /_store\z/ => { expires_in: 24*60*60 }
  plugin :upload_options, /_store\z/ => { acl: "private" }
  ```

* The `activerecord` plugin now accepts an `:attribute_types` option. When enabled, it uses `type_for_attribute` (instead of just `columns_hash`) to detect whether the data attribute is JSON/JSONB, so Shrine also skips its own serialization for attributes declared via the Active Record Attributes API (not just real database columns). It defaults to `false` for backwards compatibility with apps that might be relying on the previous double-serialization behavior.

  ```rb
  class Photo < ActiveRecord::Base # `image_data` is a text column
    include ImageUploader::Attachment(:image)

    attribute :image_data, :json
  end

  plugin :activerecord, attribute_types: true
  ```

## Bug fixes

* The `activerecord` and `sequel` plugins no longer delete the previous attachment when the record being saved was just created. Previously, duplicating a persisted record (e.g. via `#dup`) and immediately assigning a new attachment before saving the duplicate could end up deleting the *original* record's attachment, since both records shared the same underlying file.

* The `remove_invalid` plugin now correctly clears/reverts the model attribute after an invalid file is deassigned. Previously the record's raw attribute could be left out of sync with the attacher after validation failed.

* `UploadedFile#tempfile` (from the `tempfile` plugin) can now be called without opening the uploaded file first. Previously it raised `Shrine::Error` unless the file was already open; now it downloads and caches the file on demand. If the uploaded file is open, its tempfile is still cleaned up when the file is closed; otherwise it's cleaned up whenever it becomes unreachable and is garbage collected, so it's still recommended to close the uploaded file when you're done with it for deterministic cleanup.
