Upload de fichiers avec Shrine

Résumé Support

Dans cette vidéo je vous propose de découvrir une gem plutôt sympa pour l'upload de fichier : Shrine.

Shrine vs Carrierwave

Avant de détailler le fonctionnement de cette gem je pense qu'il est intéréssant de la comparer à une autre Gem qui remplit une fonction similaire : CarrierWave. D'une manière générale les 2 gems fonctionnent d'une manière similaire en créant une classe "Uploader" qui va permettre de représenter l'upload de fichier pour un model en particulier. En revanche les informations ne sont pas stockées de la même façon en base de données :

  • Shrine va sauvegarder un JSON contenant les informations concernant le fichier (nom, mime type, chemin, version...). Carrierwave ne sauvegarde que le nom du fichier et se base sur la configuration de la classe pour déterminer les différentes versions et le chemin du fichier (ce qui pose pas mal de problème lorsque l'on change de structure en milieu de projet)
  • Shrine propose une solution plus modulable que carrierwave à travers un système de plugin qui permet de rajouter ou supprimer des fonctionnalités en fonction des besoins.

Présentation

Pour commencer à utiliser Shrine il faut charger la gem

gem 'shrine'

Puis configurer le système via un initialiser

require "shrine" require "shrine/storage/file_system" Shrine.storages = { cache: Shrine::Storage::FileSystem.new("public", prefix: "uploads/cache"), # temporary store: Shrine::Storage::FileSystem.new("public", prefix: "uploads"), # permanent } Shrine.plugin :activerecord Shrine.plugin :cached_attachment_data

Les plugins peuvent être chargés globalement via cet initialiser mais peuvent aussi être activés au cas par cas dans les Uploader. Il faut ensuite créer la migration pour ajouter un champs permettant de persister l'image.

class AddImageToPosts < ActiveRecord::Migration[5.1] def change add_column :posts, :image_data, :text end end

On crée la classe pour représenter l'upload

# gem 'image_processing' # gem 'mini_magick' class ImageUploader < Shrine plugin :moving plugin :validation_helpers plugin :remove_invalid plugin :versions plugin :processing include ImageProcessing::MiniMagick process(:store) do |io, context| { original: io, small: resize_to_fill(io.download, 150, 150) } end Attacher.validate do validate_mime_type_inclusion %w[image/jpeg image/png image/gif] validate_max_size 5*1024*1024 validate_extension_inclusion %w[jpg jpeg png gif] end end

Et on peut l'inclure dans notre model

include ImageUploader::Attachment.new(:image)

Enfin, si vous souhaitez donner la possibilité à l'utilisateur d'uploader un fichier

<div class="field"> <%= form.label :image %> <%= form.text_area :image, value: post.cached_image_data %> <%= form.file_field :image %> </div>