我正在使用paperclip将我的文档上传到Amazon S3。我想在上传新文档时自动创建一个包含项目ID的存储桶。
因此,在我的控制器中,我有这个:
def new
@pmdocument = Pmdocument.new
@pmdocument.projectmilestone_id=params[:projectmilestone_id]
其中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')
当我加载页面时,我收到此错误: 用于#
的未定义方法`projectmilestone_id'我检查了控制器,并在那里正确加载了projectmilestone_id字段。
我尝试将存储桶行更改为:bucket => self.name
,然后错误就消失了。
模型工作正常,因为projectmilestone_id正确存储在数据库中。
我的猜测是它可以链接到可访问的属性,但它似乎也可以。
怎么了?非常感谢!!!
我真的不明白:
我决定不再改变我的桶了(不管怎么说,坏主意因为所有S3的名称都必须是唯一的),而是改变我的路径。
这是代码:
:path => proc { |attachment| "#{attachment.istance.projectname}/:attachment/:id/:basename.:extension" },
未创建包含项目名称的第一个文件夹。如果我按名称,甚至描述(pmdocuments的另一个字段)替换projectname,它可以工作,但不能与projectname一起使用。当然,我检查了projectname是否正确填充。原因在于别处。
有任何线索吗?
答案 0 :(得分:10)
has_attached_file
方法在类的上下文中执行(在加载文件时),而不是在可以使用属性和其他实例方法的记录实例的上下文中执行。 self.name
确实有效,但它返回类的名称("Pmdocument"
),而不是记录的名称。
但Paperclip非常友好,可以满足您的需求。 documentation on the S3 storage说:
您可以将存储桶定义为Proc if 你想确定它的名字 运行。 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')
现在您将Proc传递给has_attached_file
。在加载类时不会评估块的内容,但在以后需要时会对其进行评估。然后,Paperclip以attachment为参数调用该块,并将返回的值用作存储桶名称。
编辑:
不幸的是,此块在分配文件时运行,而不是在保存记录时运行。因此,您的所有属性可能尚未设置(当Pmdocument.new(params[:pmdocument])
未确定时,属性分配的顺序)。我想让Paperclip以另一种方式工作,但与此同时我看到了两个选择:
您可以从控制器中的参数中删除该文件,并在其他所有准备就绪时设置该文件:
pmdoc = params[:pmdocument].delete(:pmdoc)
@pmdocument = Pmdocument.new(params[:pmdocument])
@pmdocument.pmdoc = pmdoc
或者,您可以通过before_post_process
禁用Paperclip后处理来延迟它(请参阅README的“事件”部分)并在after_save
callback中运行。