2011-06-09 63 views
5

我想從舊網站導入一些圖標。這些圖標的大小不到10kb。所以當我試圖導入圖標時,它返回的stringio.txt文件。使用大小小於10kb的開放URI和回形針存儲圖像

require "open-uri" 
class Category < ActiveRecord::Base 
    has_attached_file :icon, :path => ":rails_root/public/:attachment/:id/:style/:basename.:extension" 
    def icon_from_url(url) 
    self.icon = open(url) 
    end  
end 

在rake任務中。

category = Category.new 
    category.icon_from_url "https://xyz.com/images/dog.png" 
    category.save 
+0

你試圖從其他網站獲取的圖像,具有某種問題,是嗎?爲什麼回形針的東西呢?你爲什麼不直接下載圖標並單獨上傳?你確實意識到回形針是否用於處理文件上傳,對嗎? – coreyward 2011-06-12 00:17:20

+0

我想在回形針樣式中添加圖標。有大約400個圖標..我不可能創建大量的文件夾。 – 2011-06-12 06:33:30

+0

@coreyward更多這些圖標與某些類別相關,每個類別都有很多其他細節。 – 2011-06-12 19:52:54

回答

35

嘗試:

def icon_from_url(url) 
    extname = File.extname(url) 
    basename = File.basename(url, extname) 

    file = Tempfile.new([basename, extname]) 
    file.binmode 

    open(URI.parse(url)) do |data| 
    file.write data.read 
    end 

    file.rewind 

    self.icon = file 
end 
+0

此代碼適用於第一張圖片,但沒有任何內容。我有一個350圖像的循環。我仔細檢查了鏈接。它非常好。另外圖像名稱不一樣。 – 2011-06-13 06:10:43

+0

@Mohit執行此方法後,您是否在模型上調用'save'? – 2011-06-13 16:26:11

+3

在open-uri返回的IO上設置'original_filename'更簡單快捷。 – 2011-06-18 08:37:10

1

你幾乎在那裏我想,嘗試打開解析的uri,而不是字符串。

require "open-uri" 
class Category < ActiveRecord::Base 
    has_attached_file :icon, :path =>:rails_root/public/:attachment/:id/:style/:basename.:extension" 
    def icon_from_url(url) 
    self.icon = open(URI.parse(url)) 
    end  
end 

當然,這並不處理錯誤

+0

它不會保存擴展! – 2013-10-05 21:36:30

9

要覆蓋在回形針「假文件上傳」的默認文件名(在小文件或幾乎stringio.txt大文件上的隨機臨時名稱)有兩種主要可能性:

定義IO上的original_filename

def icon_from_url(url) 
    io = open(url) 
    io.original_filename = "foo.png" 
    self.icon = io 
end 

您也可以從URI的文件名:

io.original_filename = File.basename(URI.parse(url).path) 

或者在你:path更換:basename

has_attached_file :icon, :path => ":rails_root/public/:attachment/:id/:style/foo.png", :url => "/:attachment/:id/:style/foo.png" 

記住要送花兒給人改變:url當您更改:path,否則icon.url方法將是錯誤的。

您還可以定義您自己的custom interpolations(例如:rails_root/public/:whatever)。

+3

我試圖使用這個,但如果我嘗試在io上設置original_filename, NoMethodError:未定義的方法'original_filename =' tempfile出錯。 Ruby 1.8.7 rails 2.3.8 – 2012-05-16 21:16:03

+4

@DustinM。這工作:'def io.original_filename; 「foo.png」;結束' – 2012-09-27 17:20:19

+0

我可以證實這個工作。爲了訪問一個局部變量,我不得不使用define_method: open(doc.url)do | file | file.singleton_class.instance_eval do define_method(:original_filename){doc.title} end end – 2012-11-09 20:19:00

-2

過去,我發現檢索遠程文件的最可靠方法是使用命令行工具「wget」。下面的代碼主要是從現有的生產直複製(Rails的2.X)的應用程序有一些調整,以適應您的代碼示例:

class CategoryIconImporter 
    def self.download_to_tempfile (url) 
    system(wget_download_command_for(url)) 
    @@tempfile.path 
    end 

    def self.clear_tempfile 
    @@tempfile.delete if @@tempfile && @@tempfile.path && File.exist?(@@tempfile.path) 
    @@tempfile = nil 
    end 

    def self.set_wget 
    # used for retrieval in NrlImage (and in future from other sies?) 
    if [email protected]@wget 
     stdin, stdout, stderr = Open3.popen3('which wget') 
     @@wget = stdout.gets 
     @@wget ||= '/usr/local/bin/wget' 
     @@wget.strip! 
    end 
    end 
    def self.wget_download_command_for (url) 
    set_wget 
    @@tempfile = Tempfile.new url.sub(/\?.+$/, '').split(/[\/\\]/).last 
    command = [ @@wget ] 
    command << '-q' 
    if url =~ /^https/ 
     command << '--secure-protocol=auto' 
     command << '--no-check-certificate' 
    end 
    command << '-O' 
    command << @@tempfile.path 
    command << url 
    command.join(' ') 
    end 

    def self.import_from_url (category_params, url) 
    clear_tempfile 

    filename = url.sub(/\?.+$/, '').split(/[\/\\]/).last 
    found = MIME::Types.type_for(filename) 
    content_type = !found.empty? ? found.first.content_type : nil 

    download_to_tempfile url 

    nicer_path = RAILS_ROOT + '/tmp/' + filename 
    File.copy @@tempfile.path, nicer_path 

    Category.create(category_params.merge({:icon => ActionController::TestUploadedFile.new(nicer_path, content_type, true)})) 
    end 
end 

rake任務的邏輯可能是:

[ 
    ['Cat', 'cat'], 
    ['Dog', 'dog'], 
].each do |name, icon| 
    CategoryIconImporter.import_from_url {:name => name}, "https://xyz.com/images/#{icon}.png" 
end 

這將使用MIME類型的寶石的內容類型的發現:

gem 'mime-types', :require => 'mime/types'