Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save sanjayginde/4113386 to your computer and use it in GitHub Desktop.
Save sanjayginde/4113386 to your computer and use it in GitHub Desktop.
Support setting a Paperclip attachment from a remote URL with a generic mixin for Rails

See also: http://almosteffortless.com/2008/12/11/easy-upload-via-url-with-paperclip/

Forked from: https://gist.github.com/1502777

The goal was a more generic solution to the one in gist this is forked from. It does not require the addition of any more db columns, as I choose not to store the remote URL.

Currently missing, is validation of the remote URL and error handling. Probably makes sense to just work with ActiveRecord::Errors

Currently, the file upload takes precedence over the the remote url, if a user supplies both. I'm thinking that should probably be an option flag on can_attach_remote_url.

More references:

# lib/paperclip/can_attach_from_remote_url.rb
require 'open-uri'
module Paperclip
module CanAttachFromRemoteUrl
module ClassMethods
def can_attach_from_remote_url(name)
attr_accessor "#{name}_remote_url"
before_validation "download_remote_#{name}", :if => "#{name}_remote_url_provided?"
define_method "#{name}_remote_url_provided?" do
self.send("#{name}_remote_url").present? && !self.send("#{name}").dirty?
end
define_method "download_remote_#{name}" do
begin
io = open(URI.parse(self.send("#{name}_remote_url")))
if io
def io.original_filename; base_uri.path.split('/').last; end
io.original_filename.blank? ? nil : io
send("#{name}=", io)
end
rescue
#TODO: should do some error handling (make invalid?)
# catch url errors with validations instead of exceptions (Errno::ENOENT, OpenURI::HTTPError, etc...)
end
end
end
end
module Glue
def self.included(base)
base.extend ClassMethods
end
end
end
end
# config/initializers/paperclip.rb
#... append to configuration to wire in the code
ActiveRecord::Base.send :include, Paperclip::CanAttachFromRemoteUrl::Glue
# 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_remote_url %><br>
<%= f.submit 'Submit' %>
<% end %>
# app/models/photo.rb
class Photo < ActiveRecord::Base
has_attached_file :image # etc...
can_attach_from_remote_url :image
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment