написать поток в скрепку - PullRequest
7 голосов
/ 02 марта 2011

Я хочу сохранить полученное вложение электронной почты с использованием скрепки.Из электронной почты я получаю part.body, и я понятия не имею, как поместить его в модель со скрепкой.Сейчас я создаю временный файл и записываю в него файл port.body, сохраняю этот файл в скрепке и удаляю файл.Вот как я делаю это с временным файлом:

    l_file = File.open(l_path, "w+b", 0644)
    l_file.write(part.body)
    oAsset = Asset.new(
        :email_id => email.id, 
        :asset => l_file, 
        :header => h, 
        :original_file_name => o, 
        :hash => h)
    oAsset.save
    l_file.close
    File.delete(l_path)

: актив - это мое поле has_attached_file.Есть ли способ пропустить создание файла и сделать что-то вроде:: asset => part.body в Asset.new?

Ответы [ 6 ]

21 голосов
/ 04 марта 2011

Вот как я это сделаю, если вы используете mail gem для чтения письма. вам понадобится вся электронная почта 'part', а не только part.body

file = StringIO.new(part.body) #mimic a real upload file
  file.class.class_eval { attr_accessor :original_filename, :content_type } #add attr's that paperclip needs
  file.original_filename = part.filename #assign filename in way that paperclip likes
  file.content_type = part.mime_type # you could set this manually aswell if needed e.g 'application/pdf'

теперь просто используйте объект файла для сохранения в ассоциации Paperclip.

a = Asset.new 
a.asset = file
a.save!

Надеюсь, это поможет.

9 голосов
/ 25 августа 2012

Ответ Барлоу хорош, но он эффективно исправляет класс StringIO. В моем случае я работал с Mechanize :: Download # body_io и не хотел загрязнять класс, что приводило к неожиданным ошибкам, появляющимся далеко в приложении. Поэтому я определяю методы в метаклассе экземпляров следующим образом:

original_filename = "whatever.pdf" # Set local variables for the closure below
content_type = "application/pdf"

file = StringIO.new(part.body)

metaclass = class << file; self; end
metaclass.class_eval do
  define_method(:original_filename) { original_filename }
  define_method(:content_type) { content_type }
end
6 голосов
/ 22 мая 2013

Мне очень нравится ответ gtd, но он может быть проще.

file = StringIO.new(part.body)

class << file
  define_method(:original_filename) { "whatever.pdf" }
  define_method(:content_type) { "application/pdf" }
end

Нет необходимости извлекать «метакласс» в локальную переменную, просто добавьте некоторый класс к объекту.

2 голосов
/ 24 мая 2016

Начиная с ruby ​​1.9, вы можете использовать StringIO и define_singleton_method:

def attachment_from_string(string, original_filename, content_type)
  StringIO.new(string).tap do |file|
    file.define_singleton_method(:original_filename) { original_filename }
    file.define_singleton_method(:content_type) { content_type }
  end
end
0 голосов
/ 23 мая 2019

Это было бы лучше, если бы я прокомментировал ответ Дэвида-Барлоу, но у меня пока недостаточно репутационных очков ...

Но, как уже упоминали другие, я не любил исправления обезьян.Вместо этого я просто создал новый класс, унаследованный от StringIO, например:

class TempFile < StringIO
  attr_accessor :original_filename, :content_type  
end
0 голосов
/ 02 марта 2011

Я использовал похожую технику для перетаскивания изображений в скрепку

это должно работать, но obvs не проверено:

io = part.body
def io.original_filename; part.original_file_name || 'unknown-file-name'; end

asset = Asset.new(:email=>email)
asset.asset = io

Когда мы назначаем IO непосредственно для экземпляра paperclip,ему нужно иметь имя .original_file_name, вот что мы делаем во второй строке.

...