Il file salvato in Paperclip non deve essere caricato direttamente tramite un modulo.
Sto utilizzando Paperclip in un progetto per salvare i file dagli URL dai risultati di webcrawler. Non sono sicuro di come otterresti gli allegati di posta elettronica (sono sul file system locale del server? La tua app è un'app di posta elettronica come GMail?) Ma finché puoi ottenere un flusso di file (tramite qualcosa come open(URI.parse(crawl_result))
in il mio caso ...) è possibile allegare quel file al campo del modello contrassegnato come has_attached_file
.
Questo post del blog su
Easy Upload via URL with Paperclip mi ha aiutato a capirlo.
Dal momento che ora sembra il post sul blog originale non è più disponibile - ecco l'essenza di esso tirato dalla macchina Wayback:
Questo esempio mostra un modello di foto che ha un allegato immagine.
La tecnica che stiamo utilizzando richiede l'aggiunta di una colonna *_remote_url
(stringa) per l'allegato, che viene utilizzata per memorizzare l'URL originale. Quindi, in questo caso, dobbiamo aggiungere una colonna denominata image_remote_url
alla tabella delle foto.
# 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
Niente di speciale è necessario per il controller ...
# 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
Nella forma, aggiungiamo un text_field chiamato :image_url
, così la gente può caricare un file o un 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 %>
Il materiale carnoso si trova nel modello Foto. Abbiamo bisogno di require open-uri
, aggiungere uno attr_accessor :image_url
e fare le cose normali has_attached_file
. Quindi, aggiungiamo un callback before_validation
per scaricare il file nell'attributo image_url
(se fornito) e salviamo l'URL originale come image_remote_url
. Infine, facciamo un validates_presence_of :image_remote_url
, che ci consente di salvare dalle numerose eccezioni che possono essere sollevate quando si tenta di scaricare il file.
# 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
Tutto funzionerà come normale, compresa la creazione di miniature, ecc Inoltre, dal momento che stiamo facendo tutte le cose difficili nel modello, "upload", un file tramite URL funziona dall'interno di script/console pure:
$ 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">
L'utilizzo di File.new (percorso) porta a situazioni indesiderate. Paperclip non chiude mai l'istanza File.new e questo potrebbe causare errori come "Troppi file aperti" durante l'elaborazione di molti allegati. Il codice corretto deve essere 'f = File.new (percorso logo) client.logo = f f.close' –
Commento molto buono. Non ho riscontrato questo problema perché l'ho usato su un compito molto piccolo con un piccolo numero di file. Ho aggiornato la mia soluzione - preferisco usare File.open quando possibile invece di chiudere manualmente. –
kikito