2011-06-09 33 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'