Chargement avec des rails et un trombone

Ceci est le dernier article de la série "Uploading with Rails". Au cours des deux derniers mois, nous avons déjà discuté des joyaux des sanctuaires, des libellules et des Carrierwave. L’invité d’aujourd’hui est Paperclip de Thoughtbot, une entreprise qui gère des bijoux tels que FactoryGirl et Bourbon.

Paperclip est probablement la solution de gestion des pièces jointes la plus répandue pour Rails (plus de 13 millions de téléchargements), et ce pour une bonne raison: ses nombreuses fonctionnalités, son excellente communauté et sa documentation complète. J'espère que vous avez hâte d'en savoir plus sur ce joyau!

Dans cet article, vous apprendrez comment:

  • Préparer l'installation du trombone
  • Intégrer Paperclip dans une application Rails
  • Ajouter des validations de pièces jointes
  • Générer des vignettes et traiter des images
  • Masquer les URL
  • Stocker les pièces jointes sur Amazon S3
  • Sécuriser les fichiers dans le nuage en introduisant une logique d'autorisation

Le code source de cet article est disponible sur GitHub.

Les préparatifs

Avant de plonger dans le code, discutons d’abord certaines mises en garde que vous devez connaître pour pouvoir utiliser Paperclip:

  • La dernière version de Paperclip prend en charge Rails 4.2+ et Ruby 2.1+. Ce bijou peut également être utilisé sans rails.
  • ImageMagick doit être installé sur votre PC (il est disponible pour toutes les principales plates-formes), et Paperclip doit pouvoir y accéder..
  • le fichier La commande doit être disponible à partir de la ligne de commande. Pour Windows, il est disponible via le Kit de développement. Suivez donc ces instructions si DevKit n’est pas encore installé..

Lorsque vous êtes prêt, créez une nouvelle application Rails (j'utiliserai Rails 5.0.2) sans la suite de tests par défaut:

rails nouveau UploadingWithPaperclip -T

Intégration de trombone

Déposer dans le joyau du trombone:

Gemfile

bijou "trombone", "~> 5.1"

Installez-le:

installation groupée

Supposons que nous créons une application de bibliothèque qui présente une liste de livres. Chaque livre aura un titre, une description, le nom d'un auteur et une image de couverture. Pour commencer, générez et appliquez la migration suivante:

rails g model Titre de l'ouvrage: string description: image de texte: pièce jointe auteur: string rails db: migrate

Noter la attachement type qui nous est présenté par Paperclip. Sous le capot, il va nous créer quatre champs:

  • nom_fichier_image
  • image_fichier_size
  • image_content_type
  • image_updated_at

Contrairement aux gemmes Shrine et Carrierwave, Paperclip n’a pas de fichier séparé avec des configurations. Tous les paramètres sont définis dans le modèle lui-même à l'aide du has_attached_file méthode, ajoutez-le maintenant:

modèles / book.rb

has_attached_file: image

Avant de passer à la partie principale, créons également un contrôleur avec quelques vues et itinéraires..

Création du contrôleur, des vues et des itinéraires

Notre contrôleur sera très basique:

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

Voici un indice vue et une partielle:

views / books / index.html.erb

Étagère à livres

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

consultations / livres / _book.html.erb

  • <%= link_to book.title, book_path(book) %> par <%= book.author %>
  • Maintenant les itinéraires:

    config / routes.rb

    Rails.application.routes.draw do resources: books racine à: 'books # index' end 

    Agréable! Passons maintenant à la section principale et codons le Nouveau action et une forme.

    Téléchargement de fichiers

    Dans l’ensemble, il est facile de télécharger des images avec Paperclip. Vous devez uniquement autoriser l'attribut correspondant (dans notre cas, c'est le image attribut, et nous l’avons déjà autorisé) et présente un champ de fichier dans votre formulaire. Faisons-le maintenant:

    views / books / new.html.erb

    Ajouter un livre

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

    consultations / livres / _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 %>

    Avec cette configuration, vous pouvez déjà commencer à effectuer des téléchargements, mais il est également bon de présenter quelques validations..

    Ajout de validations

    Les validations dans Paperclip peuvent être écrites en utilisant d'anciens helpers comme validates_attachment_presence et validates_attachment_content_type ou en employant le validates_attachment méthode pour définir plusieurs règles à la fois. Restons avec cette dernière option:

    modèles / book.rb

     validates_attachment: image, type_contenu: type_contenu: /\Aimage\/.***/, taille: moins_than: 1.mégaoctet

    Le code est très simple, comme vous pouvez le voir. Nous exigeons que le fichier soit une image de moins de 1 Mo de taille. Notez que si la validation échoue, aucun post-traitement ne sera effectué. Paperclip contient déjà des messages d'erreur définis pour la langue anglaise, mais si vous souhaitez prendre en charge d'autres langues, incluez la gem paperclip-i18n dans votre Gemfile.

    Une autre chose importante à noter est que Paperclip vous demande de valider le type de contenu ou le nom de fichier de toutes les pièces jointes, sinon une erreur se produira. Si vous êtes sûr à 100% de ne pas avoir besoin de telles validations (ce qui est un cas rare), utilisez do_not_validate_attachment_file_type de dire explicitement quels champs ne doivent pas être vérifiés.

    Après avoir ajouté les validations, affichons également les messages d'erreur dans notre formulaire:

    views / shared / _errors.html.erb

    <% if object.errors.any? %> 

    Quelques erreurs ont été trouvées:

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

    consultations / livres / _form.html.erb

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

    Affichage des images

    D'accord, les images téléchargées doivent maintenant être affichées. Ceci est fait en utilisant le image_tag assistant et un url méthode. Créer un spectacle vue:

    views / books / show.html.erb

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

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

    <%= @book.description %>

    Nous affichons une image uniquement si elle existe vraiment sur le lecteur. De plus, si vous utilisez le stockage en nuage, Paperclip effectuera une requête réseau et vérifiera l’existence du fichier. Bien sûr, cette opération peut prendre un certain temps, vous pouvez donc utiliser le présent? ou fichier? méthodes à la place: ils veilleront simplement à ce que le nom_fichier_image le champ est rempli avec du contenu.

    Obfuscation URI

    Par défaut, toutes les pièces jointes sont stockées dans la public / système dossier, vous voudrez probablement l'exclure du système de contrôle de version: 

    .gitignore

    public / système

    Cependant, afficher un URI complet dans le fichier n'est peut-être pas toujours une bonne idée et vous devrez peut-être le masquer d'une manière ou d'une autre. Le moyen le plus simple d’activer l’obscurcissement consiste à fournir deux paramètres à la Méthode has_attached_file:

    modèles / book.rb

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

    Les valeurs appropriées seront interpolées dans le url automatiquement. hash_secret est un champ obligatoire, et le moyen le plus simple de le générer consiste à utiliser:

    rails secret

    Travailler avec des styles

    Dans de nombreux cas, il est préférable d’afficher la vignette d’une image avec une largeur et une hauteur prédéfinies pour économiser la bande passante. Paperclip résout ce problème en utilisant des styles: chaque style a un nom et un ensemble de règles, telles que les dimensions, le format, la qualité, etc..

    Supposons que nous voulions que l'image originale et sa vignette soient converties au format JPEG. La vignette doit être recadrée à 300x300px:

    modèles / book.rb

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

    # est un paramètre de géométrie signifiant: "Rogner si nécessaire tout en conservant les proportions".

    Nous pouvons également fournir des options de conversion supplémentaires pour chaque style. Par exemple, fournissons une qualité de 70% pour les pouces tout en supprimant toutes les métadonnées et une qualité de 90% pour l'image d'origine afin de la réduire un peu:

    modèles / book.rb

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

    Agréable! Affichez la vignette et fournissez le lien vers l'image d'origine:

    views / books / show.html.erb

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

    Notez que contrairement à Carrierwave, par exemple, Paperclip ne vous permet pas d’écrire @ book.image.thumb.url.

    Si, pour une raison quelconque, vous souhaitez mettre à jour manuellement les images téléchargées, vous pouvez utiliser les commandes suivantes pour actualiser uniquement les vignettes, ajouter des styles manquants ou actualiser toutes les images:

    • rake paperclip: refresh: vignettes CLASS = Livre
    • rake paperclip: refresh: missing_styles CLASS = Livre
    • rake paperclip: refresh CLASS = Livre

    Stockage de fichiers dans le nuage

    Comme toutes les solutions similaires, Paperclip vous permet de télécharger des fichiers sur le cloud. Par défaut, il prend en charge les adaptateurs S3 et Fog, mais il existe également des joyaux tiers pour Azure et Dropbox. Dans cette section, je vais vous montrer comment intégrer Paperclip à Amazon S3. Tout d’abord, déposez la pierre précieuse aws-sdk:

    gem 'aws-sdk'

    Installez-le:

    installation groupée

    Ensuite, fournissez un nouvel ensemble d’options au has_attached_file méthode:

    modèles / book.rb

     has_attached_file: image, styles: thumb: ["300x300 #",: jpeg], original: [: jpeg], convert_options: thumb: "-quality 70 -strip", original: "-quality 90", stockage :: s3, s3_credentials: clé_accès: ENV ["S3_KEY"], secret_access_key: ENV ["S3_SECRET"], compartiment: ENV ["S3_BUCKET"]], s3_region: ENV ["S3_REGION"]

    Ici, je m'en tiens à la gem dotenv-rails pour définir les variables d'environnement. Vous pouvez fournir toutes les valeurs directement dans le modèle, mais ne le rendez pas public..

    Ce qui est intéressant c'est que s3_credentials accepte également un chemin d'accès à un fichier YAML contenant vos clés et un nom de compartiment. De plus, vous pouvez définir différentes valeurs pour différents environnements, comme ceci: 

    développement: access_key_id: key1 secret_access_key: secret1 production: access_key_id: key2 secret_access_key: secret2

    C'est tout! Tous les fichiers que vous téléchargez seront maintenant situés dans votre compartiment S3.

    Sécuriser des fichiers dans le nuage

    Supposons que vous ne voulez pas que vos fichiers téléchargés soient disponibles pour tout le monde. Par défaut, tous les téléchargements dans le nuage sont marqués comme publics, ce qui signifie que tout le monde peut ouvrir le fichier via le lien direct. Si vous souhaitez introduire une logique d’autorisation et vérifier qui peut visualiser le fichier, définissez le paramètre s3_permissions option de :privé comme ça:

     has_attached_file: image, styles: thumb: ["300x300 #",: jpeg], original: [: jpeg], convert_options: thumb: "-quality 70 -strip", original: "-quality 90", stockage :: s3, s3_credentials: clé_accès: ENV ["S3_KEY"], secret_access_key: ENV ["S3_SECRET"], compartiment: ENV ["S3_BUCKET"]], s3_region: ENV ["S3_REGION"], s3_permissions: privé

    Maintenant, cependant, personne à part vous ne pourra voir les fichiers. Par conséquent, créons un nouveau Télécharger action pour la LivresContrôleur:

    books_controller.rb

     def télécharger redirect_to @ book.image.expiring_url end

    Cette action redirigera simplement les utilisateurs vers l'image via un lien expirant. En utilisant cette approche, vous pouvez maintenant introduire toute logique d’autorisation en utilisant des gemmes comme CanCanCan ou Pundit..

    N'oubliez pas de définir la route des membres:

    config / routes.rb

     ressources: les livres ne sont-ils pas téléchargés? end end

    L'assistant devrait être utilisé comme ceci:

    link_to ('Voir l'image', download_book_path (@book), cible: '_blank')

    Conclusion

    Nous sommes arrivés à la fin de cet article! Aujourd'hui, nous avons vu Paperclip, une solution de gestion des pièces jointes pour Rails, en action et discuté de ses principaux concepts. Il y a beaucoup plus à ce bijou, alors assurez-vous de voir sa documentation.

    Je vous recommande également de consulter la page wiki de Paperclip, qui présente une liste de didacticiels "Comment faire", ainsi que de nombreux liens vers des gemmes tierces prenant en charge Azure et Cloudinary et permettant de réduire facilement les fichiers téléchargés.

    Merci de rester avec moi et à bientôt!