0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Rails初学者】もくもく会に参加して、Shrine(シュライン)というライブラリの存在を知りました

Posted at

初めて知ったShrineって何?

勉強を始めたばかりの私が、もくもく会に初めて参加させていただきました!
諸先輩方がお話ししていて耳にした「Shrine」という言葉。
調べてみると、Railsでファイルを扱うことのできるライブラリであることを知りました。
自分なりに調べたので、記事にして残します。


Shrine(シュライン)は

Shrineは、Rails標準の「Active Storage」とは異なり、 軽くて速くて自由度が高い、**ファイルアップロード用ライブラリと知りました。
画像・音声・PDF・動画など、さまざまなファイルを扱うことができ、 Active Storageの代わりとして使うことも可能らしいです。


Shrineでできること

機能 説明
プラグイン構造 必要な機能だけを読み込むモジュール設計。軽くて拡張しやすい
クラウド保存OK AWS S3・Google Cloud・Cloudinaryなどに簡単保存
メモリに優しい ストリーミング処理で大きなファイルも安定動作
Rails以外でも使える Ruby全般で利用可能
画像加工対応 MiniMagick や libvips でリサイズ・サムネイル生成
直接アップロード JavaScriptでS3へ直接アップロード可能
バックグラウンド処理 Sidekiqなどで非同期アップロード・削除
テストが簡単 メモリ上ストレージで高速テストが可能

Shrineの流れ(ざっくり)


[フォーム] → [コントローラ] → [Shrineアップローダー] → [ストレージ]
↑
[モデルに include]

ファイルをアップロードすると

  • Shrine が「一時保存 → 本保存」を行う
  • モデルに image_data(JSON形式)として情報を保存
  • 表示時に image_url でURLを取得

使い方

①Gemを追加する

# Gemfile
gem "shrine", "~> 3.0"

②初期設定する(config/initializers/shrine.rb

require "shrine"
require "shrine/storage/file_system"

Shrine.storages = {
  cache: Shrine::Storage::FileSystem.new("public", prefix: "uploads/cache"), # 一時保存
  store: Shrine::Storage::FileSystem.new("public", prefix: "uploads")        # 永続保存
}

Shrine.plugin :activerecord
Shrine.plugin :cached_attachment_data
Shrine.plugin :restore_cached_data

ActiveRecord対応、フォーム再表示時の保持が有効になるようです。


③DBにカラムを追加

rails generate migration add_image_data_to_photos image_data:text

image_data カラムにはファイルのメタ情報がJSON形式で保存されるようです。


④アップローダーを作る

# app/uploaders/image_uploader.rb
class ImageUploader < Shrine
  # ここに画像加工や検証などを追加できる
end

⑤モデルに組み込む

class Photo < ApplicationRecord
  include ImageUploader::Attachment(:image)
end

これで photo.imagephoto.image_url が使えるようになるようです。


⑥フォームを作る

<%= form_for @photo do |f| %>
  <%= f.hidden_field :image, value: @photo.cached_image_data, id: nil %>
  <%= f.file_field :image %>
  <%= f.submit "アップロード" %>
<% end %>

⑦コントローラ

def create
  Photo.create(photo_params)
end

private

def photo_params
  params.require(:photo).permit(:image)
end

⑧表示

<%= image_tag @photo.image_url %>

S3に保存する場合

require "shrine/storage/s3"

s3_options = {
  bucket: "my-bucket",
  region: "ap-northeast-1",
  access_key_id: "XXX",
  secret_access_key: "YYY",
}

Shrine.storages = {
  cache: Shrine::Storage::S3.new(prefix: "cache", **s3_options),
  store: Shrine::Storage::S3.new(**s3_options)
}

これでアップロードしたファイルが自動的にS3に保存されるようです。


Shrineの中身をざっくり理解

レイヤー 役割
Shrineクラス アップロードの基盤(プラグインを組み込む) Shrine.plugin :activerecord
Uploader Shrineを継承し、設定を書く class ImageUploader < Shrine
Attachmentモジュール モデルにincludeして利用 include ImageUploader::Attachment(:image)
Attacherクラス 実際のアップロードや削除を担当 photo.image_attacher
UploadedFile 保存されたファイルを表すオブジェクト photo.image.url

Shrineでできる応用例

MiniMagickで画像サイズを自動変換

Shrine.plugin :derivatives, create_on_promote: true
require "image_processing/mini_magick"

class ImageUploader < Shrine
  Attacher.derivatives do |original|
    magick = ImageProcessing::MiniMagick.source(original)
    {
      small:  magick.resize_to_limit!(300, 300),
      medium: magick.resize_to_limit!(600, 600)
    }
  end
end

非同期アップロード(Sidekiq)

Shrine.plugin :backgrounding
Shrine::Attacher.promote_block do
  PromoteJob.perform_async(self.class.name, record.class.name, record.id, name, file_data)
end

ブラウザから直接S3アップロード

Shrine.plugin :upload_endpoint
mount Shrine.upload_endpoint(:cache) => "/upload"

まとめ

Shrineは...

  • 大きなファイルも軽快に扱える
  • S3やSidekiqとも連携ができる
  • 画像・音声・PDFなどを扱うことができる

初学者の学び

今回は初めて「Shrine」というライブラリを知りました。
使ったことはありませんが、Active Storageの代わりに自由度の高いファイル管理ができるという点にとても興味を持ちました。
今後、自分のRailsアプリで画像や音声を扱う機能を作るときに、ぜひ一度Shrineを触ってみたいと思います。


記載内容が間違えていたら、すいません。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?