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>