Recent Projects

Easy Upload via URL with attachment_fu

Allowing file uploads with attachment_fu is super easy, but I’ve found that users sometimes want to be able to “upload” a file directly from a URL. This saves them the steps of downloading the file, finding it on their computer, uploading it into your app, etc.

I did a bit of digging around before I came across this handy trick that makes it pretty painless to add uploading via a URL to your app. I’ve wrapped up the code a bit and added in a few niceties that I found necessary to avoid raising exceptions unnecessarily.

The best part is that you don’t need to change anything about your controller in order to get this to work. All you need is to add the uri attribute to your model and views, and you’re good to go.

# app/models/upload.rb

class Upload < ActiveRecord::Base

  # ...normal attachment_fu code (has_attachment, etc)...

  # allow uploads via URL
  require 'open-uri'
  attr_reader :url
  def url=(uri)
    return nil if uri.blank?
    io = (open(URI.parse(uri)) rescue return nil)
    (class << io; self; end;).class_eval do
      define_method(:original_filename) { base_uri.path.split('/').last }
    end
    self.uploaded_data = io
  end
end

# app/controllers/uploads_controller.rb

class UploadsController < ApplicationController

  # avoid raising exceptions for common errors (e.g. file not found)
  rescue_from Errno::ENOENT, :with => :url_upload_not_found
  rescue_from Errno::ETIMEDOUT, :with => :url_upload_not_found
  rescue_from OpenURI::HTTPError, :with => :url_upload_not_found
  rescue_from Timeout::Error, :with => :url_upload_not_found

  def new
    @upload = Upload.new
  end

  def create
    @upload = current_user.uploads.build(params[:upload])
    if @upload.save
      redirect_to files_path
    else
      render :action => "new"
    end
  end

  def url_upload_not_found
    flash[:notice] = "Sorry, the URL you provided was not valid."
    redirect_to new_upload_path
  end
end

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

<%= error_messages_for :upload %>
<% form_for @upload, :html => { :multipart => true } do |f| -%>
  <%= f.file_field :uploaded_data # normal upload, or... %>
  <%= f.text_field :url # upload via url %>
  <%= submit_tag "Upload", :disable_with => "Upload" %>
<% end %>

You can see a working example of all this in El Dorado. I was bored, so I decided to try my hand at making a screencast. Check it out – it’s got an awesome soundtrack at the very least :)

If you’d like to use this for multiple models, consider refactoring it into a module that you can include elsewhere.

Hope this helps – and suggestions/improvements are always welcome!

13 Responses to “Easy Upload via URL with attachment_fu”

  1. Nuwan C. says:

    Wow. I was just thinking about how to do this. You saved me a lot of time. Thanks.

  2. Matt Polito says:

    Fantastic first try at screencasts!

  3. rohandey says:

    This is good, I have book marked it

  4. [...] Easy Upload via URL with attachment_fu – almost effortless [...]

  5. [...] file uploads lately, and I wanted to be able to accept file “uploads” with a URL. We already knew how to accomplish this with attachment_fu, and getting it working in Paperclip wasn’t too [...]

  6. Tiago Pinto says:

    This is ace. Thank you! I had a “UrlUpload” class (similar to the LocalUpload one) on one project and this tip saved my day.

    Thanks!

  7. Mark says:

    Hey,
    I was wondering how to get this to work with the resizing that attachment_fu can do? This method just uploads the image but doesn’t take into account the resize_to or the thumbnails. Any suggestions?

  8. Trevor says:

    Sorry, I’m not sure about that. I haven’t tried it, but I assumed it would work. I guess not, though!

  9. Mark says:

    Bummer, I really need this functionality and can’t figure it out at all :(

  10. Shinyi says:

    This is nice and easy.. ^_^ This sure saves me

  11. Matthew says:

    Thanks that works great!

    @Mark – It’s creating thumbnails for me.. You may have a problem with RMagick or something?

  12. Brian King says:

    Thanks a ton! Works like a charm.

  13. Unshift says:

    This is brilliance. Just saved me a lot of time.

Leave a Reply