ruby on rails - thoughtbot - Guardar archivos usando Paperclip sin cargar
paperclip rails 5 (2)
Yo tenía una pregunta rápida. ¿Es posible guardar un archivo sin subirlo a través de un formulario?
Por ejemplo, digamos que estoy viendo archivos adjuntos de correos electrónicos y quiero guardarlos con un clip. ¿Cómo hago esto? ¿Tengo que llamar manualmente a save_file (o algo similar) en algún lugar?
¡Cualquier ayuda sería muy apreciada!
El archivo guardado en Paperclip no tiene que cargarse directamente a través de un formulario.
Estoy usando Paperclip en un proyecto para guardar archivos de las URL de los resultados del webcrawler. No estoy seguro de cómo obtendrás los archivos adjuntos del 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 como has_attached_file
.
Esta publicación del blog sobre Easy Upload a través de la URL con Paperclip me ayudó a resolver esto.
Dado que ahora parece que la publicación original del blog ya no está disponible, aquí está la esencia de esto extraída de la máquina de wayback:
Este ejemplo muestra un modelo de foto que tiene una imagen adjunta.
La técnica que estamos utilizando requiere agregar una *_remote_url
(cadena) para su archivo adjunto, que se utiliza para almacenar la URL original. Entonces, en este caso, debemos 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
No se requiere nada especial 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, agregamos un text_field llamado :image_url
, para que las personas puedan subir un archivo o proporcionar 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 %>
Lo sustancioso está en el modelo de Foto. Necesitamos require open-uri
, agregar un attr_accessor :image_url
, y hacer las cosas normales de has_attached_file
. Luego, agregamos una devolución de llamada before_validation
para descargar el archivo en el atributo image_url
(si se proporciona) y image_remote_url
URL original como image_remote_url
. Finalmente, hacemos una 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 funcionará normalmente, incluida la creación de miniaturas, etc. Además, dado que estamos haciendo todas las cosas difíciles del modelo, "cargar" un archivo a través de una URL también funciona desde el script / consola:
$ 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">
Tengo una tarea de rake que carga imágenes (logotipos de clientes) desde un directorio directamente en el parperclip. Probablemente puedas adaptarlo a tus necesidades.
Este es mi modelo de cliente simplificado:
class Client < ActiveRecord::Base
LOGO_STYLES = {
:original => [''1024x768>'', :jpg],
:medium => [''256x192#'', :jpg],
:small => [''128x96#'', :jpg]
}
has_attached_file :logo,
:styles => Client::LOGO_STYLES,
:url => "/clients/logo/:id.jpg?style=:style"
attr_protected :logo_file_name, :logo_content_type, :logo_size
Entonces en mi tarea de rastrillo hago esto:
# the logos are in a folder with path logos_dir
Dir.glob(File.join(logos_dir,''*'')).each do |logo_path|
if File.basename(logo_path)[0]!= ''.'' and !File.directory? logo_path
client_code = File.basename(logo_path, ''.*'') #filename without extension
client = Client.find_by_code(client_code) #you could use the ids, too
raise "could not find client for client_code #{client_code}" if client.nil?
File.open(logo_path) do |f|
client.logo = f # just assign the logo attribute to a file
client.save
end #file gets closed automatically here
end
end
¡Saludos!