在Heroku上移动Paperclip S3附件

时间:2011-08-02 21:40:18

标签: ruby-on-rails ruby-on-rails-3 amazon-s3 heroku paperclip

我正在尝试使用Heroku,Paperclip和S3做一些非常简单的事情 - 将一个模型的附件设置为等于另一个模型。

这是我放在一起的自定义rake任务:

task :migrate => :environment do
    @companies = Company.where("attachment_file_name IS NOT NULL")    
    @companies.each do |c|
        if c.attachments.where("attachment_file_name = ?", c.attachment_file_name).blank?
        # i.e. if there are no instances of Attachment that match c.attachment
            a = Attachment.new( :company_id => c.id, :name => "Default" )
            a.attachment = c.attachment
            a.save
        end
    end
end

所以,我正在尝试将Company.attachment移动到新Attachment模型的新实例。在我的本地开发服务器上,它运行得很漂亮。

一旦推送到Heroku,我收到以下错误,指向a.attachment = c.attachment行。

The specified key does not exist.

我为在heroku控制台中有附件的公司手动尝试操作,我得到:

TypeError: can't convert nil into String
/app/.bundle/gems/ruby/1.8/gems/paperclip-2.3.6/lib/paperclip/storage/s3.rb:131:in `extname'
/app/.bundle/gems/ruby/1.8/gems/paperclip-2.3.6/lib/paperclip/storage/s3.rb:131:in `to_file'
/app/.bundle/gems/ruby/1.8/gems/paperclip-2.3.6/lib/paperclip/attachment.rb:81:in `assign'
/app/vendor/plugins/paperclip/lib/paperclip.rb:245:in `attachment='

你知道这里发生了什么吗?


我刚试过c.attachment = c.attachment。同样的错误!!!

3 个答案:

答案 0 :(得分:0)

看起来c.attachment_file_name即将出现,而回形针不知道如何处理它。我不确定为什么它是零但是为了绕过它你可以检查它是否是nill并且如果它是跳过它:

if c.attachment_file_name
    if c.attachments.where("attachment_file_name = ?", c.attachment_file_name).blank?
        # i.e. if there are no instances of Attachment that match c.attachment
        a = Attachment.new( :company_id => c.id, :name => "Default" )
        a.attachment = c.attachment
        a.save
    end
end

答案 1 :(得分:0)

您是否考虑过修改回形针模型以接受网址作为附件?通过这种方式,您可以将附件移植到新模型,而不是从根本上修改回形针s3存储机制。

将此添加到新模型中:

before_validation :download_remote_attachment, :if => :attachment_url_provided?

...

attr_accessor :attachment_url

  private

  def attachment_url_provided?
    !self.attachment_url.blank?
  end

  def download_remote_attachment
    self.file = do_download_remote_image
  end

  def do_download_remote_attachment
    io = open(attachment_url)
    def io.original_filename; base_uri.path.split('/').last; end
    io.original_filename.blank? ? nil : io
  rescue
  end   

然后创建一个新的附件对象,将参数:attachment_url传递给它,它将下载它,重新处理它,并将其存储为新模型的附件。唯一的缺点是附件将在S3上存储两次。根据您的应用程序要求,这可能是一件好事

答案 2 :(得分:0)

在黑暗中还有一个远射,来自“为什么它与开发db和非生产db一起工作”的角度。是否有机会attachment通过has_many :through关系提供?如果连接表中添加了主键,则可以阅读mySQL可能发生的这种类型的奇怪错误。虽然可以使用sqLite3。所以,一旦你去生产,就会看到错误。只是一个想法。