Search code examples
ruby-on-railsrubyshrine

Rails 5 + Shrine multiple files upload


I am trying to implement multiple files upload using polymorphic association and Shrine.

class Campaign < ApplicationRecord
  has_many :photos, as: :imageable, dependent: :destroy
  accepts_nested_attributes_for :photos, allow_destroy: true
end

class Photo < ApplicationRecord
  include ImageUploader::Attachment.new(:image)
  belongs_to :imageable, polymorphic: true
end

I am able to save the photos after going through the docs.
Please advise how to validate uniqueness of image in scope of imageable.
I know that a signature could be generated per original version, but is it a right way to go?
Thanks.


Solution

  • Generating a signature is the only way to tell whether two files have the same content without loading both these files into memory (which you should always avoid). Also, using a signature means you can use database uniqueness constraints and/or ActiveRecord uniqueness validations if you save the signature into a column.

    This is how you could do it with Shrine:

    # db/migrations/001_create_photos.rb
    create_table :photos do |t|
      t.integer :imageable_id
      t.string  :imageable_type
      t.text    :image_data
      t.text    :image_signature
    end
    add_index :photos, :image_signature, unique: true
    
    # app/uploaders/image_uploader.rb
    class ImageUploader < Shrine
      plugin :signature
      plugin :add_metadata
      plugin :metadata_attributes :md5 => :signature
    
      add_metadata(:md5) { |io| calculate_signature(io) }
    end
    
    # app/models/image.rb
    class Photo < ApplicationRecord
      include ImageUploader::Attachment.new(:image)
      belongs_to :imageable, polymorphic: true
    
      validates_uniqueness_of :image_signature
    end