Search code examples
ruby-on-railsruby-on-rails-3amazon-s3paperclipfog

Associate object to pre-existing file on S3, using Paperclip


I have a file already on S3 that I'd like to associate to a pre-existing instance of the Asset model.

Here's the model:

class Asset < ActiveRecord::Base
  attr_accessible(:attachment_content_type, :attachment_file_name,
                 :attachment_file_size, :attachment_updated_at, :attachment)

  has_attached_file :attachment, {
    storage: :s3,
    s3_credentials: {
      access_key_id: ENV['AWS_ACCESS_KEY_ID'],
      secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'],
    },
    convert_options: { all: '-auto-orient' },
    url: ':s3_alias_url',
    s3_host_alias: ENV['S3_HOST_ALIAS'],
    path: ":class/:attachment/:id_partition/:style/:filename",
    bucket: ENV['S3_BUCKET_NAME'],
    s3_protocol: 'https'
  }
end

Let's say the path is assets/attachments/000/111/file.png, and the Asset instance I want to associate with the file is asset. Referring at the source, I've tried:

options = {
    storage: :s3,
    s3_credentials: {
      access_key_id: ENV['AWS_ACCESS_KEY_ID'],
      secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'],
    },
    convert_options: { all: '-auto-orient' },
    url: ':s3_alias_url',
    s3_host_alias: ENV['S3_HOST_ALIAS'],
    path: "assets/attachments/000/111/file.png",
    bucket: ENV['S3_BUCKET_NAME'],
    s3_protocol: 'https'
  }
# The above is identical to the options given in the model, except for the path

Paperclip::Attachment.new("file.png", asset, options).save

As far as I can tell, this did not affect asset in any way. I cannot set asset.attachment.path manually.

Other questions on SO do not seem to address this specifically. "paperclip images not saving in the path i've set up", "Paperclip and Amazon S3 how to do paths?", and so on involve setting up the model, which is already working fine.

Anyone have any insight to offer?


Solution

  • As far as I can tell, I do need to turn the S3 object into a File, as suggested by @oregontrail256. I used the Fog gem to do this.

    s3 = Fog::Storage.new(
            :provider => 'AWS',
            :aws_access_key_id => ENV['AWS_ACCESS_KEY_ID'],
            :aws_secret_access_key => ENV['AWS_SECRET_ACCESS_KEY']
          )
    
    directory = s3.directories.get(ENV['S3_BUCKET_NAME'])
    fog_file = directory.files.get(path)
    
    file = File.open("temp", "wb")
    file.write(fog_file.body)
    asset.attachment = file
    asset.save
    file.close