2009-11-03 53 views
31

我有一個簡單的問題。是否可以保存文件而不需要通過表單上傳文件?使用回形針保存文件無需上傳

例如,假設我正在查看來自電子郵件的附件,並且我想使用回形針保存它們。我該怎麼做呢?我是否需要手動調用save_file(或類似的東西)?

任何幫助將不勝感激!

回答

46

我有一個加載直接從目錄圖片(客戶端標識)到parperclip rake任務。你可能可以適應你的需求。

這是我的簡化客戶端模式:

class Client < ActiveRecord::Base 
    LOGO_STYLES = { 
    :original => ['1024x768>', :jpg], 
    :medium => ['256x192#', :jpg], 
    :small => ['128x96#', :jpg] 
    } 

    has_attached_file :logo, 
    :styles => Client::LOGO_STYLES, 
    :url => "/clients/logo/:id.jpg?style=:style" 
    attr_protected :logo_file_name, :logo_content_type, :logo_size 

然後在我的耙子任務我這樣做:

# the logos are in a folder with path logos_dir 
Dir.glob(File.join(logos_dir,'*')).each do |logo_path| 
    if File.basename(logo_path)[0]!= '.' and !File.directory? logo_path 

    client_code = File.basename(logo_path, '.*') #filename without extension 
    client = Client.find_by_code(client_code) #you could use the ids, too 
    raise "could not find client for client_code #{client_code}" if client.nil? 

    File.open(logo_path) do |f| 
     client.logo = f # just assign the logo attribute to a file 
     client.save 
    end #file gets closed automatically here 
    end 
end 

商祺!

+4

使用File.new(路徑)會導致不需要的情況。 Paperclip從不關閉File.new實例,這可能會導致在處理大量附件時出現諸如「打開的文件太多」等錯誤。正確的代碼應該是 'f = File.new(logo_path) client.logo = f f.close' – 2012-04-02 10:30:08

+2

非常好的評論。我沒有遇到這個問題,因爲我用一個很小的任務來處理少量的文件。我更新了我的解決方案 - 我更喜歡使用File.open ,而不是手動關閉。 – kikito 2012-04-02 17:47:27

11

保存在Paperclip中的文件不需要直接通過表單上傳。

我在項目中使用Paperclip來保存來自webcrawler結果的URL的文件。我不確定你會如何得到電子郵件附件(它們是否在服務器的本地文件系統上?您的應用程序是否爲GMail這樣的電子郵件應用程序?),但只要您可以獲取文件流(通過類似於open(URI.parse(crawl_result))我的情況...),您可以將該文件附加到標記爲has_attached_file的模型字段。

這個博客文章關於 Easy Upload via URL with Paperclip幫我弄明白了。

由於現在看來原來的博客文章不再可用 - 這裏是它從Wayback機器拉要點:

這個例子表明,具有圖像附件的照片模式。

的技術,我們正在使用需要添加一個*_remote_url(字符串)列的附件,這是用來存儲原始URL。因此,在這種情況下,我們需要添加一個名爲image_remote_url的照片列。

# db/migrate/20081210200032_add_image_remote_url_to_photos.rb 

class AddImageRemoteUrlToPhotos < ActiveRecord::Migration 
    def self.up 
    add_column :photos, :image_remote_url, :string 
    end 

    def self.down 
    remove_column :photos, :image_remote_url 
    end 
end 

沒有什麼特別需要控制器...

# app/controllers/photos_controller.rb 

class PhotosController < ApplicationController 

    def create 
    @photo = Photo.new(params[:photo]) 
    if @photo.save 
     redirect_to photos_path 
    else 
     render :action => 'new' 
    end 
    end 

end 

在窗體中,我們添加了一個名爲text_field :image_url,使人們可以上傳文件或提供一個網址...

# app/views/photos/new.html.erb 

<%= error_messages_for :photo %> 
<% form_for :photo, :html => { :multipart => true } do |f| %> 
    Upload a photo: <%= f.file_field :image %><br> 
    ...or provide a URL: <%= f.text_field :image_url %><br> 
    <%= f.submit 'Submit' %> 
<% end %> 

的肉的東西是在照片模式。我們需要require open-uri,添加一個attr_accessor :image_url,並做正常has_attached_file的東西。然後,我們添加一個before_validation回調下載在image_url屬性(如果有的話)的文件和原始URL保存爲image_remote_url。最後,我們做了validates_presence_of :image_remote_url,這使我們能夠從衆多的例外,可以嘗試下載該文件時提高搶救。

# app/models/photo.rb 

require 'open-uri' 

class Photo < ActiveRecord::Base 

    attr_accessor :image_url 

    has_attached_file :image # etc... 

    before_validation :download_remote_image, :if => :image_url_provided? 

    validates_presence_of :image_remote_url, :if => :image_url_provided?, :message => 'is invalid or inaccessible' 

private 

    def image_url_provided? 
    !self.image_url.blank? 
    end 

    def download_remote_image 
    self.image = do_download_remote_image 
    self.image_remote_url = image_url 
    end 

    def do_download_remote_image 
    io = open(URI.parse(image_url)) 
    def io.original_filename; base_uri.path.split('/').last; end 
    io.original_filename.blank? ? nil : io 
    rescue # catch url errors with validations instead of exceptions (Errno::ENOENT, OpenURI::HTTPError, etc...) 
    end 

end 

一切都將恢復正常,包括創建縮略圖等另外,因爲我們做的所有硬的東西在模型中,「上傳」通過URL將文件從腳本/控制檯內工作還有:

$ script/console 
Loading development environment (Rails 2.2.2) 
>> Photo.new(:image_url => 'http://www.google.com/intl/en_ALL/images/logo.gif') 
=> #<Photo image_file_name: "logo.gif", image_remote_url: "http://www.google.com/intl/en_ALL/images/logo.gif"> 
+0

甜!非常感謝! – 2009-11-05 18:26:38

+0

@Nate感謝您的評論。看起來鏈接不再起作用? – 2013-12-16 19:45:39

+0

這對於下載大文件而言非常耗費內存。其次,爲小於10KB的文件返回一個StringIO,並且如果回形針做了內容類型驗證,則這將失敗,因爲字符串沒有內容類型。 – maletor 2014-01-17 23:37:49