Caricamento con Rails e Paperclip

Questo è l'ultimo articolo nella serie "Caricamento con rotaie". Negli ultimi due mesi abbiamo già discusso le gemme Shrine, Dragonfly e Carrierwave. L'ospite di oggi è Paperclip di Thoughtbot, una società che gestisce gemme come FactoryGirl e Bourbon.

Paperclip è probabilmente la soluzione di gestione degli allegati più popolare per Rails (oltre 13 milioni di download), e per una buona ragione: ha molte funzionalità, una grande community e una documentazione completa. Quindi spero che tu sia desideroso di saperne di più su questa gemma!

In questo articolo imparerai come:

  • Preparati per l'installazione di Paperclip
  • Integrare Paperclip in un'applicazione Rails
  • Aggiungi convalide degli allegati
  • Genera miniature ed elabora immagini
  • Offuscare gli URL
  • Archivia gli allegati su Amazon S3
  • Proteggi i file nel cloud introducendo la logica dell'autorizzazione

Il codice sorgente per questo articolo è disponibile su GitHub.

preparativi

Prima di immergerci nel codice, esaminiamo innanzitutto alcune avvertenze che è necessario conoscere per poter lavorare con successo con Paperclip:

  • L'ultima versione di Paperclip supporta Rails 4.2+ e Ruby 2.1+. Questa gemma può anche essere usata senza Rails.
  • ImageMagick deve essere installato sul PC (è disponibile per tutte le principali piattaforme) e Paperclip dovrebbe essere in grado di accedervi.
  • Il file il comando dovrebbe essere disponibile dalla riga di comando. Per Windows è disponibile tramite il kit di sviluppo, quindi segui queste istruzioni se non hai ancora installato DevKit.

Quando sei pronto, vai avanti e crea una nuova applicazione Rails (userò Rails 5.0.2) senza la suite di test predefinita:

rota nuovo UploadingWithPaperclip -T

Paperclip integrato

Lascia cadere la gemma Paperclip:

Gemfile

gem "paperclip", "~> 5.1"

Installalo:

installazione bundle

Supponiamo di creare un'applicazione per scaffali che presenti un elenco di libri. Ogni libro avrà un titolo, una descrizione, il nome dell'autore e un'immagine di copertina. Per iniziare, genera e applica la seguente migrazione:

rails g model Titolo del libro: descrizione stringa: testo immagine: allegato autore: string rails db: migrate

Notare la attaccamento tipo che ci viene presentato da Paperclip. Sotto il cofano, creeremo quattro campi per noi:

  • image_file_name
  • IMAGE_FILE_SIZE
  • image_content_type
  • image_updated_at

In contrasto con le gemme Shrine e Carrierwave, Paperclip non ha un file separato con configurazioni. Tutte le impostazioni sono definite all'interno del modello stesso utilizzando has_attached_file metodo, quindi aggiungilo ora:

modelli / book.rb

has_attached_file: image

Prima di procedere alla parte principale, creiamo anche un controller con alcune viste e percorsi.

Creazione di controller, viste e percorsi

Il nostro controller sarà molto semplice:

books_controller.rb

classe BooksController < ApplicationController before_action :set_book, only: [:show, :download] def index @books = Book.order('created_at DESC') end def new @book = Book.new end def show end def create @book = Book.new(book_params) if @book.save redirect_to books_path else render :new end end private def book_params params.require(:book).permit(:title, :description, :image, :author) end def set_book @book = Book.find(params[:id]) end end

Ecco un indice vista e parziale:

views / libri / index.html.erb

Bookshelf

<%= link_to 'Add book', new_book_path %>
    <%= render @books %>

views / libri / _book.html.erb

  • <%= link_to book.title, book_path(book) %> di <%= book.author %>
  • Ora i percorsi:

    config / routes.rb

    Rails.application.routes.draw fa risorse: i libri sono rootati a: 'books # index' end 

    Bello! Ora passiamo alla sezione principale e digitiamo il codice nuovo azione e una forma.

    Caricamento di file

    Tutto sommato, fare caricamenti con Paperclip è facile. Devi solo permettere l'attributo corrispondente (nel nostro caso quello è il Immagine attributo, e lo abbiamo già autorizzato) e presentare un campo file nel modulo. Facciamolo adesso:

    views / libri / new.html.erb

    Aggiungi un libro

    <%= render 'form', book: @book %>

    views / libri / _form.html.erb

    <%= form_for book do |f| %> 
    <%= f.label :title %> <%= f.text_field :title %>
    <%= f.label :author %> <%= f.text_field :author %>
    <%= f.label :description %> <%= f.text_area :description %>
    <%= f.label :image %> <%= f.file_field :image %>
    <%= f.submit %> <% end %>

    Con questa configurazione, puoi già iniziare a eseguire caricamenti, ma è consigliabile introdurre anche alcune convalide.

    Aggiunta di convalide

    Le convalide in Paperclip possono essere scritte usando vecchi aiutanti come validates_attachment_presencevalidates_attachment_content_type o impiegando il validates_attachment metodo per definire più regole contemporaneamente. Rimaniamo con quest'ultima opzione:

    modelli / book.rb

     validates_attachment: image, content_type: content_type: /\Aimage\/.*\z/, size: less_than: 1.megabyte

    Il codice è davvero semplice, come puoi vedere. Richiediamo che il file sia un'immagine di dimensioni inferiori a 1 megabyte. Si noti che se la convalida fallisce, non verrà eseguita alcuna post-elaborazione. Paperclip ha già alcuni messaggi di errore impostati per la lingua inglese, ma se vuoi supportare altre lingue, includi la gemma paperclip-i18n nel tuo Gemfile.

    Un'altra cosa importante da ricordare è che Paperclip richiede di convalidare il tipo di contenuto o il nome del file di tutti gli allegati, altrimenti genererà un errore. Se sei sicuro al 100% che non hai bisogno di tali convalide (che è un caso raro), usa do_not_validate_attachment_file_type per dire esplicitamente quali campi non dovrebbero essere controllati.

    Dopo aver aggiunto le convalide, mostriamo anche i messaggi di errore nel nostro modulo:

    views / shared / _errors.html.erb

    <% if object.errors.any? %> 

    Alcuni errori sono stati trovati:

      <% object.errors.full_messages.each do |message| %>
    • <%= message %>
    • <% end %>
    <% end %>

    views / libri / _form.html.erb

    <%= render 'shared/errors', object: book %>

    Visualizzazione delle immagini

    Ok, quindi ora le immagini caricate dovrebbero essere visualizzate in qualche modo. Questo viene fatto usando il image_tag aiutante e a url metodo. Creare un mostrare vista:

    views / libri / show.html.erb

    <%= @book.title %> di <%= @book.author %>

    <%= image_tag(@book.image.url) if @book.image.exists? %>

    <%= @book.description %>

    Stiamo visualizzando un'immagine solo se esiste realmente sul disco. Inoltre, se si utilizza l'archiviazione cloud, Paperclip eseguirà una richiesta di rete e verificherà l'esistenza del file. Naturalmente, questa operazione potrebbe richiedere del tempo, quindi potresti usare il presente? o file? metodi invece: si accerteranno semplicemente che il image_file_name il campo è popolato con alcuni contenuti.

    Offuscamento URI

    Per impostazione predefinita, tutti gli allegati sono memorizzati all'interno di / Sistema pubblico cartella, quindi probabilmente vorrai escluderla dal sistema di controllo della versione: 

    .gitignore

    / Sistema pubblico

    Tuttavia, la visualizzazione di un intero URI nel file potrebbe non essere sempre una buona idea e potrebbe essere necessario nasconderla in qualche modo. Il modo più semplice per abilitare l'offuscamento consiste nel fornire due parametri a metodo has_attached_file:

    modelli / book.rb

    url: "/system/:hash.:extension", hash_secret: "longSecretString"

    I valori corretti saranno interpolati nel url automaticamente. hash_secret è un campo obbligatorio e il modo più semplice per generarlo è utilizzando:

    rotaie segrete

    Lavorare con gli stili

    In molti casi, è preferibile visualizzare la miniatura di un'immagine con larghezza e altezza predefinite per risparmiare larghezza di banda. Paperclip risolve questo usando gli stili: ogni stile ha un nome e un insieme di regole, come dimensioni, formato, qualità, ecc.

    Supponiamo che vogliamo che l'immagine originale e la sua miniatura siano convertite in formato JPEG. La miniatura dovrebbe essere ritagliata a 300x300px:

    modelli / book.rb

     has_attached_file: image, styles: thumb: ["300x300 #",: jpeg], originale: [: jpeg]

    # è un'impostazione della geometria che significa: "Ritaglia se necessario mantenendo le proporzioni".

    Possiamo anche fornire opzioni di conversione aggiuntive per ogni stile. Ad esempio, forniamo il 70% di qualità per i pollici rimuovendo tutti i metadati e il 90% di qualità per l'immagine originale per renderla un po 'più piccola:

    modelli / book.rb

     has_attached_file: image, styles: thumb: ["300x300 #",: jpeg], originale: [: jpeg], convert_options: thumb: "-quality 70 -strip", originale: "-quality 90"

    Bello! Visualizzare la miniatura e fornire il collegamento all'immagine originale:

    views / libri / show.html.erb

    <%= link_to(image_tag(@book.image.url(:thumb)), @book.image.url, target: '_blank') if @book.image.exists? %> 

    Nota che a differenza di Carrierwave, ad esempio, Paperclip non ti consente di scrivere @ book.image.thumb.url.

    Se, per qualche motivo, desideri aggiornare manualmente le immagini caricate, puoi utilizzare i seguenti comandi per aggiornare solo le anteprime, aggiungere gli stili mancanti o aggiornare tutte le immagini:

    • rake paperclip: refresh: thumbnails CLASS = Book
    • rake paperclip: refresh: missing_styles CLASS = Book
    • rake paperclip: refresh CLASS = Book

    Memorizzazione di file nel cloud

    Come tutte le soluzioni simili, Paperclip ti consente di caricare file nel cloud. Fuori dalla scatola, ha il supporto per gli adattatori S3 e Fog, ma ci sono anche gemme di terze parti per Azure e Dropbox. In questa sezione, ti mostrerò come integrare Paperclip con Amazon S3. Innanzitutto, inserisci la gemma aws-sdk:

    gemma 'aws-sdk'

    Installalo:

    installazione bundle

    Quindi, fornire un nuovo set di opzioni al has_attached_file metodo:

    modelli / book.rb

     has_attached_file: image, styles: thumb: ["300x300 #",: jpeg], originale: [: jpeg], convert_options: thumb: "-quality 70 -strip", originale: "-quality 90", memoria :: s3, s3_credentials: access_key_id: ENV ["S3_KEY"], secret_access_key: ENV ["S3_SECRET"], bucket: ENV ["S3_BUCKET"], s3_region: ENV ["S3_REGION"]

    Qui mi attengo alla gemma dotenv-rails per impostare le variabili d'ambiente. È possibile fornire tutti i valori direttamente all'interno del modello, ma non renderlo pubblicamente disponibile.

    Quello che è interessante è quello s3_credentials accetta anche un percorso per un file YAML contenente le chiavi e un nome bucket. Inoltre, puoi impostare valori diversi per ambienti diversi come questo: 

    sviluppo: access_key_id: key1 secret_access_key: secret1 produzione: access_key_id: key2 secret_access_key: secret2

    Questo è tutto! Tutti i file che carichi verranno ora posizionati nel tuo bucket S3.

    Protezione dei file nel cloud

    Supponiamo che tu non voglia che i tuoi file caricati siano disponibili per tutti. Per impostazione predefinita, tutti gli upload nel cloud sono contrassegnati come pubblici, il che significa che chiunque può aprire il file tramite il collegamento diretto. Se si desidera introdurre una logica di autorizzazione e verificare chi è in grado di visualizzare il file, impostare il s3_permissions opzione a :privato come questo:

     has_attached_file: image, styles: thumb: ["300x300 #",: jpeg], originale: [: jpeg], convert_options: thumb: "-quality 70 -strip", originale: "-quality 90", memoria :: s3, s3_credentials: access_key_id: ENV ["S3_KEY"], secret_access_key: ENV ["S3_SECRET"], bucket: ENV ["S3_BUCKET"], s3_region: ENV ["S3_REGION"], s3_permissions:: private

    Ora, tuttavia, nessuno tranne te sarà in grado di vedere i file. Pertanto, creiamo un nuovo Scaricare azione per il BooksController:

    books_controller.rb

     def scarica redirect_to @ book.image.expiring_url end

    Questa azione semplicemente reindirizzerà gli utenti all'immagine tramite un link in scadenza. Utilizzando questo approccio, è ora possibile introdurre qualsiasi logica di autorizzazione utilizzando gemme come CanCanCan o Pundit.

    Non dimenticare di impostare la rotta del membro:

    config / routes.rb

     risorse: i membri del libro ottengono il termine "download"

    L'helper dovrebbe essere usato in questo modo:

    link_to ('Visualizza immagine', download_book_path (@book), target: '_blank')

    Conclusione

    Siamo arrivati ​​alla fine di questo articolo! Oggi abbiamo visto in azione Paperclip, una soluzione di gestione degli allegati per Rails, che ne ha discusso i concetti principali. C'è molto di più in questa gemma, quindi assicurati di vedere la sua documentazione.

    Inoltre, ti consiglio di visitare la pagina wiki di Paperclip in quanto presenta un elenco di esercitazioni "how to" e una serie di collegamenti a gemme di terze parti che supportano Azure e Cloudinary e che ti consentono di minimizzare facilmente i file caricati.

    Grazie per essere stato con me, e a presto!