具有动态存储桶名称的 Rails 回形针 S3

发布于 2024-11-07 08:59:01 字数 1449 浏览 0 评论 0原文

我正在使用回形针将文档上传到 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

毁梦 2024-11-14 08:59:01

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

但回形针很友善,可以满足您的要求。 有关 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')

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

编辑:

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

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

pmdoc = params[:pmdocument].delete(:pmdoc)
@pmdocument = Pmdocument.new(params[:pmdocument])
@pmdocument.pmdoc = pmdoc

或者您可以通过禁用它来延迟 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:

You can define the bucket as a Proc if
you want to determine it’s name at
runtime. Paperclip will call that Proc
with attachment as the only argument.

In your case it would be something like this:

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

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:

pmdoc = params[:pmdocument].delete(:pmdoc)
@pmdocument = Pmdocument.new(params[:pmdocument])
@pmdocument.pmdoc = pmdoc

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 an after_save callback.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文