Le fichier enregistré dans Paperclip ne doit pas être téléchargé directement via un formulaire.
J'utilise Paperclip dans un projet pour enregistrer des fichiers à partir d'URL à partir des résultats de webcrawler. Je ne sais pas comment vous obtiendriez les pièces jointes (sont-elles sur le système de fichiers local du serveur? Votre application est-elle une application de messagerie comme GMail?) Mais aussi longtemps que vous pouvez obtenir un flux de fichier (via quelque chose comme open(URI.parse(crawl_result))
mon cas ...) vous pouvez attacher ce fichier à votre champ de modèle qui est marqué has_attached_file
.
Ce billet de blog sur
Easy Upload via URL with Paperclip m'a aidé à comprendre cela.
Comme il apparaît maintenant le message blog n'est plus disponible - est ici l'essentiel de celui-ci tiré de la machine à remonter le temps:
Cet exemple montre un modèle de photo qui a une image en pièce jointe.
La technique que nous utilisons nécessite l'ajout d'une colonne *_remote_url
(chaîne) pour votre pièce jointe, qui est utilisée pour stocker l'URL d'origine. Donc, dans ce cas, nous devons ajouter une colonne nommée image_remote_url
la table des photos.
# 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
Rien de spécial est nécessaire pour le contrôleur ...
# 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
Dans la forme, on ajoute un text_field appelé :image_url
, afin que les gens peuvent télécharger un fichier ou fournir une 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 substance charnue est dans le modèle photo. Nous devons require open-uri
, ajouter un attr_accessor :image_url
, et faire les choses normales has_attached_file
. Ensuite, nous ajoutons un rappel before_validation
pour télécharger le fichier dans l'attribut image_url
(si fourni) et enregistrer l'URL d'origine en tant que image_remote_url
. Enfin, nous faisons un validates_presence_of :image_remote_url
, ce qui nous permet de sauver des nombreuses exceptions qui peuvent être soulevées lors de la tentative de téléchargement du fichier.
# 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
Tout fonctionne normalement, y compris la création de vignettes, etc. De plus, puisque nous faisons tous les trucs dur dans le modèle, « ajout » un fichier via l'URL fonctionne à partir de script/console ainsi:
$ 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'utilisation de File.new (chemin) conduit à des situations indésirables. Paperclip ne ferme jamais l'instance File.new et cela peut conduire à des erreurs telles que "Trop de fichiers ouverts" lors du traitement de beaucoup de pièces jointes. Le code correct devrait être 'f = File.new (logo_path) client.logo = f f.close' –
Très bon commentaire. Je n'ai pas rencontré ce problème parce que je l'ai utilisé sur une très petite tâche avec un petit nombre de fichiers. J'ai mis à jour ma solution - Je préfère utiliser File.open autant que possible au lieu de fermer manuellement. –
kikito