JQ Blog

Shrine Gemについて

  • shrineとは

公式サイトには

Shrine is a toolkit for file attachments in Ruby applications.

と書いてある。つまり、ShrineはRubyアプリケーションにおいてファイルをアタッチするために使えるツールキットである。

  • 使い方
    • gemのインストール
      gem 'shrine'
    
    • 初期設定
      # config/initializers/shrine.rb
      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/store"), # permanent
      }
    
      Shrine.plugin :activerecord
      Shrine.plugin :cached_attachment_data # for forms
    
    • Model
      class Photo < ApplicationRecord
        include ImageUploader[:image]
      end
    
    • Uploader
      class ImageUploader < Shrine
      end
    
    • Controller
      Controllerのparamはimage_dataではなく、imageにする。
      def photo_params
        params.require(:photo).permit(:name, :image)
      end
    

ビューを作ってブラウザーで確認してみると、


大きすぎる。。!!

  • リサイズ
    リサイズのためには他のgemをインストールする必要がある。

    • gemのインストール
      gem 'image_processing'
      gem 'mini_magick', '>= 4.3.5'
    
    • Uploader編集
      require 'image_processing/mini_magick'
      class ImageUploader < Shrine
        include ImageProcessing::MiniMagick
        plugin :processing
        plugin :versions   # enable Shrine to handle a hash of files
        plugin :delete_raw # delete processed files after uploading
    
        process(:store) do |io, context|
          original = io.download
    
          size_800 = resize_to_limit!(original, 800, 800) { |cmd| cmd.auto_orient } # orient rotated images
          size_500 = resize_to_limit(size_800,  500, 500)
          size_300 = resize_to_limit(size_500,  300, 300)
    
          {original: io, large: size_800, medium: size_500, small: size_300}
        end
      end
    
    • ビューで表示する ビューでサイズ別の画像を取得できる。
      = image_tag, @photo.image[:original].url
      = image_tag, @photo.image[:large].url}
      = image_tag, @photo.image[:medium].url}"
      = image_tag, @photo.image[:small].url}"
    

    ビューで確認すると、

  • バリデーションの追加
    Uploadにバリデーションをかけるのももちろんできる。
    validation_helpersのプラグインを追加し、バリデーションを追加する。
    バリデーションの処理はAttacher.validateの中に記述する。

    • Uploaderの編集
      require 'image_processing/mini_magick'
      class ImageUploader < Shrine
        include ImageProcessing::MiniMagick
        plugin :processing
        plugin :versions   # enable Shrine to handle a hash of files
        plugin :delete_raw # delete processed files after uploading
        plugin :validation_helpers
    
        process(:store) do |io, context|
          original = io.download
    
          size_800 = resize_to_limit!(original, 800, 800) { |cmd| cmd.auto_orient } # orient rotated images
          size_500 = resize_to_limit(size_800,  500, 500)
          size_300 = resize_to_limit(size_500,  300, 300)
    
          {original: io, large: size_800, medium: size_500, small: size_300}
        end
    
        Attacher.validate do
          validate_max_size 5 * 1024 * 1024, message: 'Image is too large (max is 5 MB)'
          validate_mime_type_inclusion %w(image/jpeg image/jpg image/png)
        end
      end
    

    バリデーションにかかったら

      photo = Photo.new
      photo.image = File.open("img.png")
      photo.valid? #=> false
      photo.errors.to_hash #=> {image: ["Image is too large (max is 5 MB)"]}
    
  • Direct uploads
    • gemのインストール
      gem 'aws-sdk', '~> 2.1'
      gem 'roda'
    
    • config/initializers/shrine.rbファイルの編集
      require "shrine/storage/s3"
    
      s3_options = {
        access_key_id:     "abc",
        secret_access_key: "123",
        region:            "my-region",
        bucket:            "my-bucket",
      }
    
      Shrine.storages = {
        cache: Shrine::Storage::S3.new(prefix: "cache", **s3_options),
        store: Shrine::Storage::S3.new(prefix: "store", **s3_options),
      }
    
    • Uploaderにpluginの追加
      plugin :direct_upload
    
    • routes.rbにmount追加
      Rails.application.routes.draw do
        mount ImageUploader::UploadEndpoint => "/images"
      end
    
    • jsonの取得

    GET /images/cache/presignのrouteでjsonを取得できる。

      # GET /images/cache/presign
      {
        "url" => "https://my-bucket.s3-eu-west-1.amazonaws.com",
        "fields" => {
          "key" => "cache/b7d575850ba61b44c8a9ff889dfdb14d88cdc25f8dd121004c8",
          "policy" => "eyJleHBpcmF0aW9uIjoiMjAxNS0QwMToxMToyOVoiLCJjb25kaXRpb25zIjpbeyJidWNrZXQiOiJzaHJpbmUtdGVzdGluZyJ9LHsia2V5IjoiYjdkNTc1ODUwYmE2MWI0NGU3Y2M4YTliZmY4OGU5ZGZkYjE2NTQ0ZDk4OGNkYzI1ZjhkZDEyMTAwNGM4In0seyJ4LWFtei1jcmVkZW50aWFsIjoiQUtJQUlKRjU1VE1aWlk0NVVUNlEvMjAxNTEwMjQvZXUtd2VzdC0xL3MzL2F3czRfcmVxdWVzdCJ9LHsieC1hbXotYWxnb3JpdGhtIjoiQVdTNC1ITUFDLVNIQTI1NiJ9LHsieC1hbXotZGF0ZSI6IjIwMTUxMDI0VDAwMTEyOVoifV19",
          "x-amz-credential" => "AKIAIJF55TMZYT6Q/20151024/eu-west-1/s3/aws4_request",
          "x-amz-algorithm" => "AWS4-HMAC-SHA256",
          "x-amz-date" => "20151024T001129Z",
          "x-amz-signature" => "c1eb634f83f96b69bd675f535b3ff15ae184b102fcba51e4db5f4959b4ae26f4"
        }
      }
    

こう設定すると、ひとまずs3にdirect_uploadはできる。
公式documentにはjQuery-File-Upload, Dropzone, FineUploaderなどのJavaScriptファイルアップロードライブラリとも連携もできると書いてあるので、次は今のプロジェクトで使用しているDropzoneとの連携を調べてみる。

参照

Shrine githubページ
RailsでShrineを使ってファイルをS3にダイレクトアップロードするときの注意点
Shrineを使って画像をアップロードする