具有动态存储桶名称的 Rails 回形针 S3
我正在使用回形针将文档上传到 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')
当我加载页面时,我收到此错误: undefined method `projectmilestone_id' for #
我检查了我的控制器,projectmilestone_id 字段已正确加载到那里。
我尝试将存储桶行更改为 :bucket => self.name
然后错误就消失了。
该模型工作正常,因为 projectmilestone_id 已正确存储在数据库中。
我的猜测是它可以链接到可访问的属性,但似乎也可以。
怎么了?非常感谢!
我真的不明白:
我决定不再更改我的存储桶(无论如何都是坏主意,因为名称对于所有 S3 来说都必须是唯一的),而是更改我的路径。
这是代码:
:path => proc { |attachment| "#{attachment.istance.projectname}/:attachment/:id/:basename.:extension" },
未创建带有我的项目名称的第一个文件夹。如果我用名称替换项目名称,甚至用描述(pmdocuments 的另一个字段)替换项目名称,它可以工作,但不能用项目名称替换。当然,我检查了项目名称是否正确填充。原因在别处。
有什么线索吗?
I'm using paperclip to upload my documents to Amazon S3. I would like to automatically create a bucket with the ID of my projects when I upload a new document.
Therefore, in my controller, I have this:
def new
@pmdocument = Pmdocument.new
@pmdocument.projectmilestone_id=params[:projectmilestone_id]
where projectmilestone_id is the foreign_key to my project (to be used as my bucket name)
My model is like this:
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')
When I load the page, I get this error:
undefined method `projectmilestone_id' for #
I checked my controller and the projectmilestone_id field is correctly loaded there.
I tried to change the bucket line to :bucket => self.name
and then the error is gone.
The model works ok because projectmilestone_id is correctly stored in the db.
My guess is that it could be linked to the accessible attributes but it seems to be ok too.
What's wrong? Many thanks!!!
I really dont get it:
I decided not to change my bucket anymore (bad idea anyway as the name need to be unique for all S3) but to change my path instead.
This is the code:
:path => proc { |attachment| "#{attachment.istance.projectname}/:attachment/:id/:basename.:extension" },
The first folder with my project name is not created. If I replace projectname by name, or even description (another field of pmdocuments), it works, but not with projectname. Of course, I checked that projectname is correctly populated. The reason is elsewhere.
Any clue?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
has_attached_file
方法在类的上下文中执行(加载文件时),而不是在可以使用属性和其他实例方法的记录实例的上下文中执行。self.name
确实有效,但它返回类的名称 ("Pmdocument"
),而不是记录的名称。但回形针很友善,可以满足您的要求。 有关 S3 存储的文档说:
在你的情况下,它会是这样的:
现在你将 Proc 传递给
has_attached_file
。加载类时不会评估块的内容,而是在稍后需要时评估。 Paperclip 然后使用 附件 作为参数调用块,并使用返回的值作为存储桶名称。编辑:
不幸的是,该块在分配文件时运行,而不是在保存记录时运行。因此,您的所有属性可能尚未设置(当您执行
Pmdocument.new(params[:pmdocument])
时属性的分配顺序尚未确定)。我希望 Paperclip 以另一种方式工作,但同时我看到 2 个选项:您可以从控制器中的参数中删除文件,并在其他一切准备就绪时设置它:
或者您可以通过禁用它来延迟 Paperclip 后处理使用
before_post_process
(请参阅 README 的事件部分)并运行它位于after_save
回调中。The
has_attached_file
method is executed in the context of the class (when the file is loaded), not in the context of a record instance where you could use attributes and other instance method.self.name
works indeed, but it returns the name of the class ("Pmdocument"
), not the name of a record.But Paperclip is kind enough to allow what you want. The documentation on the S3 storage says:
In your case it would be something like this:
Now you pass a Proc to
has_attached_file
. The content of the block is not evaluated while your class is loaded, but later when it's needed. Paperclip then calls the block with the attachment as argument and uses the returned value as bucket name.Edit:
Unfortunately, this block is run when the file is assigned, not when the record is saved. So all your attributes may not be set yet (the order of the assignment of the attributes when you do
Pmdocument.new(params[:pmdocument])
is undetermined). I'd like Paperclip to work another way, but in the meantime I see 2 options:You can remove the file from the params in the controller and set it when everything else is ready:
Or you can delay Paperclip post-processing by disabling it with
before_post_process
(see the Events section of the README) and running it in anafter_save
callback.