shrinerb / shrine

File Attachment toolkit for Ruby applications

Home Page:https://shrinerb.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

content-disposition not being set

masudhossain opened this issue · comments

Can't tell what i'm doing wrong. Here's my shrine.rb below. The resulting content-dispostion stays default, which is inline; filename="Screenshot at Feb 09 10-09-57.png"; filename*=UTF-8''filenamepng

require "shrine/storage/s3"

s3_options = {
  access_key_id:     Rails.application.secrets.digitalocean_spaces_key,
  secret_access_key: Rails.application.secrets.digitalocean_spaces_secret,
  region:            Rails.application.secrets.digitalocean_spaces_region,
  endpoint:          'https://nyc3.digitaloceanspaces.com',
  bucket:            Rails.application.secrets.digitalocean_spaces_bucket,
}

Shrine.storages = {
  # Shrine::Storage::S3.new(public: true, **s3_options)
  cache: Shrine::Storage::S3.new(public: true, prefix: "cache", upload_options: {acl: "public-read"}, **s3_options),
  store: Shrine::Storage::S3.new(public: true, prefix: "store", upload_options: {acl: "public-read"}, **s3_options),
}
Shrine.plugin :activerecord
Shrine.plugin :cached_attachment_data # for retaining the cached file across form redisplays
Shrine.plugin :restore_cached_data # re-extract metadata when attaching a cached file
Shrine.plugin :uppy_s3_multipart # load the plugin
Shrine.plugin :backgrounding # adds background processing

Shrine.plugin :presign_endpoint, presign_options: -> (request) do
  # Uppy will send the "filename" and "type" query parameters 
  filename = request.params["filename"]
  type     = request.params["type"]
 
  { 
    content_disposition: ContentDisposition.attachment(filename), # download with original filename 
    content_type: type,                                # set correct content type 
  }
end

It would appear that it might get overwritten here when copying the cached file to permanent storage. You should be able to use the upload_options plugin to set the attachment content disposition on upload to permanent storage.

As this doesn't appear to be a bug in the content_disposition gem, I will move this issue to the Shrine repository.

It would appear that it might get overwritten here when copying the cached file to permanent storage. You should be able to use the upload_options plugin to set the attachment content disposition on upload to permanent storage.

As this doesn't appear to be a bug in the content_disposition gem, I will move this issue to the Shrine repository.

require "shrine/storage/s3"
require "content_disposition"

s3_options = {
  access_key_id:     Rails.application.secrets.digitalocean_spaces_key,
  secret_access_key: Rails.application.secrets.digitalocean_spaces_secret,
  region:            Rails.application.secrets.digitalocean_spaces_region,
  endpoint:          'https://nyc3.digitaloceanspaces.com',
  bucket:            Rails.application.secrets.digitalocean_spaces_bucket,
}

Shrine.storages = {
  # Shrine::Storage::S3.new(public: true, **s3_options)
  cache: Shrine::Storage::S3.new(public: true, prefix: "cache", upload_options: {acl: "public-read", content_disposition: ContentDisposition.attachment("Download name")}, **s3_options),
  store: Shrine::Storage::S3.new(public: true, prefix: "store", upload_options: {acl: "public-read", content_disposition: ContentDisposition.attachment("Download name")}, **s3_options),
}

# Check https://shrinerb.com/docs/plugins/activerecord for full list of plugins around ActiveRecord
# Check https://shrinerb.com/docs/external/extensions for full list of plugins/extensions
Shrine.plugin :activerecord
Shrine.plugin :cached_attachment_data # for retaining the cached file across form redisplays
Shrine.plugin :restore_cached_data # re-extract metadata when attaching a cached file
Shrine.plugin :uppy_s3_multipart # load the plugin
Shrine.plugin :backgrounding # adds background processing

Updated to upload_options to include ContentDisposition.attachment("Download name") for both cache and store. Still cones up at inline.

Note: All i'm trying to do is create a link that'll allow my users to download the file instead of just viewing it. So if there's another solution to this, i'm very much open to it.

The code you posted looks like it should correctly set :content_disposition to attachment. Are you able to reproduce this behaviour with AWS S3? It's possible this is an issue with Digital Ocean Spaces.

For me the last example works on AWS S3, so it seems it's an issue with DigitalOcean Spaces. Here is a self-contained example showing my recommended configuration:

require "shrine"
require "shrine/storage/s3"
require "content_disposition"
require "rack/test"
require "http"

s3_options = {
  access_key_id:     ENV.fetch("S3_ACCESS_KEY_ID"),
  secret_access_key: ENV.fetch("S3_SECRET_ACCESS_KEY"),
  region:            ENV.fetch("S3_REGION"),
  bucket:            ENV.fetch("S3_BUCKET"),
}

Shrine.storages = {
  cache: Shrine::Storage::S3.new(public: true, prefix: "cache", **s3_options),
  store: Shrine::Storage::S3.new(public: true, prefix: "store", **s3_options),
}

Shrine.plugin :presign_endpoint, presign_options: -> (request) do
  # Uppy will send the "filename" and "type" query parameters 
  filename = request.params["filename"]
  type     = request.params["type"]

  {
    content_disposition: ContentDisposition.attachment(filename), # download with original filename 
    content_type: type,                                # set correct content type 
  }
end

Shrine.plugin :upload_options, store: -> (io, options) do
  { content_disposition: ContentDisposition.attachment(io.original_filename) }
end

# imitate Uppy's presign request
presign_endpoint = Shrine.presign_endpoint(:cache)
session = Rack::Test::Session.new(presign_endpoint)
session.get("/?filename=foo.txt&type=text/plain")
data = JSON.parse(session.last_response.body)
# imitate Uppy's upload request
HTTP.post(data["url"], form: data["fields"].merge(file: HTTP::FormData::Part.new("foobar")))

cached_file = Shrine.uploaded_file(id: data["fields"]["key"].match("cache/").post_match, storage: :cache, metadata: { filename: "foo.txt" })

attacher = Shrine::Attacher.new
attacher.attach_cached(cached_file)
attacher.promote

object = attacher.store.storage.object(attacher.file.id)
object.head.content_disposition # => "attachment; filename=\"foo.txt\"; filename*=UTF-8''foo.txt"