2009-11-03 30 views
31

Ho fatto una breve domanda. È possibile salvare un file senza effettivamente caricarlo tramite un modulo?Salvare i file usando Paperclip senza upload

Ad esempio, supponiamo di guardare gli allegati dalle e-mail e voglio salvarli utilizzando una graffetta. Come faccio a fare questo? Devo chiamare manualmente un file di salvataggio (o qualcosa di simile) da qualche parte?

Qualsiasi aiuto sarebbe molto apprezzato!

risposta

46

Ho un compito rake che carica le immagini (logo dei clienti) da una directory direttamente sul parperclip. Probabilmente puoi adattarlo alle tue esigenze.

questo è il mio semplificata modello client:

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 

Poi, il mio compito rake faccio questo:

# 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 

Saluti!

+4

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' –

+2

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

11

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"> 
+0

Dolce! Molte grazie! –

+0

@Nate Grazie per questo commento. Sembra che il link non funzioni più? –

+0

Questa operazione richiede una notevole quantità di memoria per il download di file di grandi dimensioni. In secondo luogo, viene restituito un StringIO per file inferiori a 10 KB e se paperclip esegue la convalida del tipo di contenuto, ciò non riuscirà perché le stringhe non hanno tipi di contenuto. – maletor

Problemi correlati