El archivo guardado en Paperclip no tiene que ser cargado directamente a través de un formulario.
estoy usando Paperclip en un proyecto para guardar archivos de direcciones URL de los resultados WebCrawler. No estoy seguro de cómo obtendrás los archivos adjuntos de correo electrónico (¿están en el sistema de archivos local del servidor? ¿Es tu aplicación una aplicación de correo electrónico como GMail?) Pero siempre y cuando obtengas un archivo (a través de algo como open(URI.parse(crawl_result))
en mi caso ...) puede adjuntar ese archivo a su campo modelo que está marcado has_attached_file
.
Esta entrada de blog sobre
Easy Upload via URL with Paperclip me ayudó a resolver esto.
Desde ahora parece el blog original ya no está disponible - aquí está el quid de la cuestión sacado de Wayback Machine:
Este ejemplo muestra un modelo de la foto que tiene un archivo adjunto de imagen.
La técnica que estamos utilizando requiere agregar una columna *_remote_url
(cadena) para su archivo adjunto, que se utiliza para almacenar la URL original. Entonces, en este caso, necesitamos agregar una columna llamada image_remote_url
la tabla de fotos.
# db/migrate/20081210200032_add_image_remote_url_to_photos.rb
class AddImageRemoteUrlToPhotos < ActiveRecord::Migration
def self.up
add_column :photos, :image_remote_url, :string
end
def self.down
remove_column :photos, :image_remote_url
end
end
Nada especial que se requiere para el controlador ...
# 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
En el formulario, añadimos una llama text_field :image_url
, por lo que la gente puede subir un archivo o una URL ...
# 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_url %><br>
<%= f.submit 'Submit' %>
<% end %>
la materia carnosa está en el modelo de la foto. Necesitamos require open-uri
, agregar un attr_accessor :image_url
, y hacer las cosas normales has_attached_file
. A continuación, añadimos una devolución de llamada before_validation
para descargar el archivo en el atributo image_url
(si se proporciona) y guardar la URL original como image_remote_url
. Finalmente, hacemos un validates_presence_of :image_remote_url
, que nos permite rescatar de las muchas excepciones que pueden surgir al intentar descargar el archivo.
# app/models/photo.rb
require 'open-uri'
class Photo < ActiveRecord::Base
attr_accessor :image_url
has_attached_file :image # etc...
before_validation :download_remote_image, :if => :image_url_provided?
validates_presence_of :image_remote_url, :if => :image_url_provided?, :message => 'is invalid or inaccessible'
private
def image_url_provided?
!self.image_url.blank?
end
def download_remote_image
self.image = do_download_remote_image
self.image_remote_url = image_url
end
def do_download_remote_image
io = open(URI.parse(image_url))
def io.original_filename; base_uri.path.split('/').last; end
io.original_filename.blank? ? nil : io
rescue # catch url errors with validations instead of exceptions (Errno::ENOENT, OpenURI::HTTPError, etc...)
end
end
Todo va a trabajar de forma normal, incluyendo la creación de miniaturas, etc. Además, puesto que estamos haciendo todas las cosas difíciles en el modelo, "subir" un archivo a través de URL funciona desde dentro de la escritura/consola así:
$ script/console
Loading development environment (Rails 2.2.2)
>> Photo.new(:image_url => 'http://www.google.com/intl/en_ALL/images/logo.gif')
=> #<Photo image_file_name: "logo.gif", image_remote_url: "http://www.google.com/intl/en_ALL/images/logo.gif">
El uso de File.new (ruta) conduce a situaciones no deseadas. Paperclip nunca cierra la instancia File.new y esto puede generar errores como "Demasiados archivos abiertos" al procesar muchos archivos adjuntos. El código correcto debe ser 'f = File.new (logo_path) client.logo = f f.close' –
Muy buen comentario. No acerté ese problema porque lo usé en una tarea muy pequeña con una pequeña cantidad de archivos. He actualizado mi solución: prefiero utilizar File.open siempre que sea posible en lugar de cerrar manualmente. –
kikito