скрепка рельсов S3 с динамическим названием ковша - PullRequest
8 голосов
/ 12 мая 2011

Я использую скрепку для загрузки своих документов в Amazon S3.Я хотел бы автоматически создать корзину с идентификатором моих проектов при загрузке нового документа.

Поэтому в моем контроллере у меня есть это:

 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), это работает, но не с именем проекта.Конечно, я проверил, что имя проекта правильно заполнено.Причина в другом месте.

Есть подсказка?

1 Ответ

10 голосов
/ 12 мая 2011

Метод has_attached_file выполняется в контексте класса (при загрузке файла), а не в контексте экземпляра записи, где вы можете использовать атрибуты и другой метод экземпляра. self.name действительно работает, но возвращает имя класса ("Pmdocument"), а не имя записи.

Но Paperclip достаточно любезен, чтобы позволить то, что вы хотите. Документация о хранилище S3 гласит:

Вы можете определить ведро как 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 вызывает блок с вложением в качестве аргумента и использует возвращенное значение в качестве имени сегмента.

Edit:

К сожалению, этот блок запускается при назначении файла, а не при сохранении записи. Поэтому все ваши атрибуты могут быть еще не установлены (порядок назначения атрибутов, когда вы делаете Pmdocument.new(params[:pmdocument]), не определен). Я бы хотел, чтобы Paperclip работал по-другому, но пока я вижу 2 варианта:

Вы можете удалить файл из params в контроллере и установить его, когда все остальное будет готово:

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

Или вы можете отложить постобработку Paperclip, отключив ее с помощью before_post_process (см. Раздел «События» README ) и запустив ее в обратном вызове after_save .

...