Apprendre Ruby on RailsUpload de fichiers avec Shrine

Télécharger la vidéo

Introduction
Controllers
Models
Vues
Aller plus loin
Travaux Pratiques
TP : Gestion des animauxRéservé aux membres premiums
57 min
TP : Gestion des photosRéservé aux membres premiums
46 min
TP : Création du système de FollowersRéservé aux membres premiums
52 min
Les gems utiles
Notions avancées

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>