rails paperclip S3具有动态存储桶名称

nde*_*eau 8 ruby-on-rails amazon-s3 paperclip

我正在使用paperclip将我的文档上传到Amazon S3.我想在上传新文档时自动创建一个包含项目ID的存储桶.

因此,在我的控制器中,我有这个:

 def new
    @pmdocument = Pmdocument.new
    @pmdocument.projectmilestone_id=params[:projectmilestone_id]
Run Code Online (Sandbox Code Playgroud)

其中projectmilestone_id是我项目的foreign_key(用作我的桶名)

我的模型是这样的:

class Pmdocument < ActiveRecord::Base
  belongs_to :projectmilestone
  attr_accessible :id, :name, :description, :projectmilestone_id, :pmdoc, :projectmilestone_attributes
  attr_protected :pmdoc_content_type, :pmdoc_size
  accepts_nested_attributes_for :projectmilestone, :allow_destroy => false
  has_attached_file :pmdoc,
    :storage => :s3,
    :bucket => self.projectmilestone_id.to_s,
    :s3_credentials => File.join(Rails.root, 'config', 's3.yml')
Run Code Online (Sandbox Code Playgroud)

当我加载页面时,我收到此错误:未定义的方法`projectmilestone_id'for#

我检查了我的控制器,并在那里正确加载了projectmilestone_id字段.

我试图将铲斗线更改为:bucket => self.name然后错误消失了.

该模型工作正常,因为projectmilestone_id正确存储在db中.

我的猜测是它可以链接到可访问的属性,但它似乎也可以.

怎么了?非常感谢!!!


我真的不明白:

我决定不再改变我的桶了(不管怎样,坏主意因为所有S3的名称都必须是唯一的),而是改变我的路径.

这是代码:

:path => proc { |attachment| "#{attachment.istance.projectname}/:attachment/:id/:basename.:extension" },
Run Code Online (Sandbox Code Playgroud)

未创建具有项目名称的第一个文件夹.如果我按名称,甚至描述(pmdocuments的另一个字段)替换projectname,它可以工作,但不能与projectname一起使用.当然,我检查了projectname是否正确填充.原因在于其他地方.

任何线索?

Mic*_*ant 10

has_attached_file方法在类的上下文中执行(在加载文件时),而不是在可以使用属性和其他实例方法的记录实例的上下文中执行.self.name确实有效,但它返回class("Pmdocument")的名称,而不是记录的名称.

但Paperclip非常友好,可以满足您的需求.有关S3存储文档说:

如果要在运行时确定其名称,可以将存储桶定义为Proc.Paperclip会将附件作为唯一参数调用Proc.

在你的情况下,它将是这样的:

has_attached_file :pmdoc,
  :storage => :s3,
  :bucket => proc { |attachment| attachment.instance.projectmilestone_id.to_s },
  :s3_credentials => File.join(Rails.root, 'config', 's3.yml')
Run Code Online (Sandbox Code Playgroud)

现在你将Proc传递给has_attached_file.在加载类时不会评估块的内容,但在以后需要时会对其进行评估.然后,Paperclip使用附件作为参数调用块,并将返回的值用作存储桶名称.

编辑:

不幸的是,这个块在分配文件时运行,而不是在保存记录时运行.因此,您的所有属性可能尚未设置(当您执行操作时,属性分配的顺序Pmdocument.new(params[:pmdocument])未确定).我想让Paperclip以另一种方式工作,但与此同时我看到两个选择:

您可以从控制器中的参数中删除该文件,并在其他所有准备就绪时设置该文件:

pmdoc = params[:pmdocument].delete(:pmdoc)
@pmdocument = Pmdocument.new(params[:pmdocument])
@pmdocument.pmdoc = pmdoc
Run Code Online (Sandbox Code Playgroud)

或者您可以通过禁用Paperclip后处理before_post_process(参见README的Events部分)并在after_save回调中运行它来延迟Paperclip后处理.