Storing image using open URI and paperclip having size less than 10kb

11,652

Solution 1

Try:

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

Solution 2

To override the default filename of a "fake file upload" in Paperclip (stringio.txt on small files or an almost random temporary name on larger files) you have 2 main possibilities:

Define an original_filename on the IO:

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

You can also get the filename from the URI:

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

Or replace :basename in your :path:

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

Remember to alway change the :url when you change the :path, otherwise the icon.url method will be wrong.

You can also define you own custom interpolations (e.g. :rails_root/public/:whatever).

Solution 3

You are almost there I think, try opening parsed uri, not the string.

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

Of course this doesn't handle errors

Solution 4

You can also disable OpenURI from ever creating a StringIO object, and force it to create a temp file instead. See this SO answer:

Why does Ruby open-uri's open return a StringIO in my unit test, but a FileIO in my controller?

Share:
11,652
Mohit Jain
Author by

Mohit Jain

warning ! This is just a rip-off my linkedin profile :D Seasoned Web Developer with over 8 years of work experience, with focus on code quality, scaling, timely delivery, under pressure working experience and performance optimization. My responsibilities in the past ranged from designing and implementing large scalable systems, managing and monitoring clusters of servers, and also mentoring junior engineers and managing project teams. I'm always interested in hands-on contributions to challenging and innovative projects. Good interpersonal skills. Uncompromising work ethic and integrity. Known for quickly ramping up on new code bases and incorporating massive design changes in existing systems. Clean and efficient programming style. Excellent debugging practices, used to work in code written by different people. In the last few years, I wrote tens of thousands of lines of code to scale a system from 1 million users to 20 million users single-handedly. Specialities: Ruby on Rails, Redis, Memcache, MySQL, New Relic, Amazon Web Services, Over night prototyping, Mixpanel

Updated on June 14, 2022

Comments

  • Mohit Jain
    Mohit Jain almost 2 years

    I want to import some icons from my old site. The size of those icons is less than 10kb. So when I am trying to import the icons its returning stringio.txt file.

    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
    

    In rake task.

       category = Category.new
       category.icon_from_url "https://xyz.com/images/dog.png"
       category.save
    
  • Mohit Jain
    Mohit Jain almost 13 years
    this code worked for the first image but then nothing. I have a loop of some 350 images. I double checked the links. its perfectly fine. In addition image name is not the same.
  • Kevin Sylvestre
    Kevin Sylvestre almost 13 years
    @Mohit Are you calling save on your model after performing this method?
  • Michaël Witrant
    Michaël Witrant almost 13 years
    Setting original_filename on the IO returned by open-uri is much simpler and faster.
  • Dustin M.
    Dustin M. about 12 years
    I am trying to use this but if I try to set original_filename on io in this example I am getting an NoMethodError: undefined method `original_filename=' Error on the tempfile. Ruby 1.8.7 rails 2.3.8
  • Matstar
    Matstar over 11 years
    @DustinM. This works: def io.original_filename; "foo.png"; end
  • Paul Brannan
    Paul Brannan over 11 years
    I can confirm that this works. In order to access a local variable, I had to use define_method: open(doc.url) do |file| file.singleton_class.instance_eval do define_method(:original_filename) { doc.title } end end
  • Nadeem Yasin
    Nadeem Yasin over 10 years
    Its not going to save extenstion!
  • mpoisot
    mpoisot over 10 years
    @MichaëlWitrant I found that PaperClip 3.5.1 performs MIME type validations based on the Tempfile's filename. It doesn't matter if original_filename is set. I used @KevinSylvestre's method to force the Tempfile to have the correct extension, and thus PaperClip "guessed" the correct MIME type. (You could argue that the validation is useless in this scenario, but having the correct MIME type stored in the DB might be useful.)
  • Joshua Plicque
    Joshua Plicque about 8 years
    This doesn't work due to the undefined method error.