RailsとShrineを使用したファイルのアップロード
いくつか例を挙げると、CarrierWave、Paperclip、Dragonflyなどのファイルアップロードの宝石がたくさんあります。それらはすべて固有のものを持っており、おそらくあなたはすでにこれらの宝石の少なくとも1つを使用しています。
しかし、今日は、JankoMarohnićによって作成されたShrineと呼ばれる比較的新しいが非常にクールなソリューションを紹介したいと思います。他のいくつかの同様の宝石とは対照的に、それはモジュール式のアプローチを持っています。つまり、すべての機能がモジュール(またはプラグイン)としてパックされています。 神社の用語で)。検証をサポートしたいですか?プラグインを追加します。ファイル処理をしたいですか?プラグインを追加してください!どのモデルでどの機能を利用できるかを簡単に制御できるので、このアプローチが本当に気に入っています。
この記事では、次の方法を紹介します。
- ShrineをRailsアプリケーションに統合する
- 構成(グローバルおよびアップローダーごと)
- ファイルをアップロードする機能を追加する
- ファイルを処理する
- 検証ルールを追加
- 追加のメタデータを保存し、AmazonS3でファイルクラウドストレージを採用する
この記事のソースコードはGitHubで入手できます。
動作するデモはここにあります。
神社の統合
まず、デフォルトのテストスイートを使用せずに新しいRailsアプリケーションを作成します。
rails new FileGuru -T
このデモではRails5を使用しますが、ほとんどの概念はバージョン3と4にも当てはまります。
神社の宝石をGemfileにドロップします:
gem "shrine"
次に実行します:
bundle install
次に、 Photo
と呼ぶモデルが必要になります。 。 Shrineは、ファイル関連のすべての情報を、 _data
で終わる特別なテキスト列に保存します。 サフィックス。対応する移行を作成して適用します:
rails g model Photo title:string image_data:text rails db:migrate
Railsの古いバージョンの場合、後者のコマンドは次のようになります。
rake db:migrate
神社の設定オプションは、グローバルとモデルごとの両方で設定できます。もちろん、グローバル設定は初期化ファイル内で行われます。そこで、必要なファイルとプラグインを接続します。 。プラグインはShrineで使用され、機能の一部を個別のモジュールに抽出して、使用可能なすべての機能を完全に制御できるようにします。たとえば、検証、画像処理、添付ファイルのキャッシュなどのプラグインがあります。
今のところ、2つのプラグインを追加しましょう。1つはActiveRecordをサポートするためのもので、もう1つはロギングを設定するためのものです。それらはグローバルに含まれる予定です。また、ファイルシステムストレージを設定します:
config / initializers / shrine.rb
require "shrine" require "shrine/storage/file_system" Shrine.plugin :activerecord Shrine.plugin :logging, logger: Rails.logger Shrine.storages = { cache: Shrine::Storage::FileSystem.new("public", prefix: "uploads/cache"), store: Shrine::Storage::FileSystem.new("public", prefix: "uploads/store"), }
Loggerは、ファイルの処理に費やされた時間を示すデバッグ情報をコンソール内に出力するだけです。これは便利です。
2015-10-09T20:06:06.676Z #25602: STORE[cache] ImageUploader[:avatar] User[29543] 1 file (0.1s) 2015-10-09T20:06:06.854Z #25602: PROCESS[store]: ImageUploader[:avatar] User[29543] 1-3 files (0.22s) 2015-10-09T20:06:07.133Z #25602: DELETE[destroyed]: ImageUploader[:avatar] User[29543] 3 files (0.07s)
アップロードされたすべてのファイルは、 public / uploads内に保存されます ディレクトリ。 Gitでこれらのファイルを追跡したくないので、このフォルダーを除外します:
.gitignore
public/uploads
次に、モデル固有の設定をホストする特別な「アップローダー」クラスを作成します。今のところ、このクラスは空になります:
models / image_uploader.rb
class ImageUploader < Shrine end
最後に、このクラスを Photo
に含めます モデル:
models / photo.rb
include ImageUploader[:image]
[:image]
フォームを作成するときに使用される仮想属性を追加します。上記の行は次のように書き直すことができます:
include ImageUploader.attachment(:image) # or include ImageUploader::Attachment.new(:image)
良い!これで、モデルに神社の機能が追加され、次のステップに進むことができます。
コントローラー、ビュー、ルート
このデモでは、写真を管理するために必要なコントローラーは1つだけです。 index
ページがルートとして機能します:
pages_controller.rb
class PhotosController < ApplicationController def index @photos = Photo.all end end
ビュー:
views / photos / index.html.erb
<h1>Photos</h1> <%= link_to 'Add Photo', new_photo_path %> <%= render @photos %>
@photos
をレンダリングするには 配列、パーシャルが必要です:
views / photos / _photo.html.erb
<div> <% if photo.image_data? %> <%= image_tag photo.image_url %> <% end %> <p><%= photo.title %> | <%= link_to 'Edit', edit_photo_path(photo) %></p> </div>
image_data?
レコードに画像があるかどうかをチェックするActiveRecordによって提示されるメソッドです。
image_url
元の画像へのパスを返すだけのShrineメソッドです。もちろん、代わりに小さなサムネイルを表示する方がはるかに優れていますが、後で処理します。
必要なルートをすべて追加します:
config / routers.rb
resources :photos, only: [:new, :create, :index, :edit, :update] root 'photos#index'
これで完了です。基礎が完成し、興味深い部分に進むことができます!
ファイルのアップロード
このセクションでは、実際にファイルをアップロードする機能を追加する方法を説明します。コントローラのアクションは非常に簡単です:
photos_controller.rb
def new @photo = Photo.new end def create @photo = Photo.new(photo_params) if @photo.save flash[:success] = 'Photo added!' redirect_to photos_path else render 'new' end end
唯一の落とし穴は、強力なパラメータの場合、 image
を許可する必要があるということです。 image_data
ではなく、仮想属性 。
photos_controller.rb
private def photo_params params.require(:photo).permit(:title, :image) end
new
を作成します ビュー:
views / photos / new.html.erb
<h1>Add photo</h1> <%= render 'form' %>
フォームの部分も簡単です:
views / photos / _form.html.erb
<%= form_for @photo do |f| %> <%= render "shared/errors", object: @photo %> <%= f.label :title %> <%= f.text_field :title %> <%= f.label :image %> <%= f.file_field :image %> <%= f.submit %> <% end %>
繰り返しになりますが、 image
を使用していることに注意してください image_data
ではなく属性 。
最後に、エラーを表示するために別のパーシャルを追加します:
views / shared / _errors.html.erb
<% if object.errors.any? %> <h3>The following errors were found:</h3> <ul> <% object.errors.full_messages.each do |message| %> <li><%= message %></li> <% end %> </ul> <% end %>
これでほぼすべてです。今すぐ画像のアップロードを開始できます。
検証
もちろん、デモアプリを完成させるには、さらに多くの作業を行う必要があります。主な問題は、ユーザーがあらゆる種類のファイルをあらゆるサイズでアップロードする可能性があることです。これは特に優れているわけではありません。したがって、検証をサポートする別のプラグインを追加します。
config / inititalizers / shrine.rb
Shrine.plugin :validation_helpers
ImageUploader
の検証ロジックを設定します :
models / image_uploader.rb
Attacher.validate do validate_max_size 1.megabyte, message: "is too large (max is 1 MB)" validate_mime_type_inclusion ['image/jpg', 'image/jpeg', 'image/png'] end
1MB未満のJPGおよびPNG画像のみのアップロードを許可しています。必要に応じて、これらのルールを微調整してください。
MIMEタイプ
注意すべきもう1つの重要な点は、デフォルトでは、ShrineはContent-TypeHTTPヘッダーを使用してファイルのMIMEタイプを決定することです。このヘッダーはブラウザによって渡され、ファイルの拡張子のみに基づいて設定されますが、これは必ずしも望ましいとは限りません。
ファイルの内容に基づいてMIMEタイプを決定する場合は、determine_mime_typeというプラグインを使用します。他のモデルはこの機能を必要としない可能性があるため、アップローダークラスに含めます:
models / image_uploader.rb
plugin :determine_mime_type
このプラグインは、デフォルトでLinuxのファイルユーティリティを使用します。
添付画像のキャッシュ
現在、ユーザーが誤ったデータを含むフォームを送信すると、フォームは再び表示され、上記のエラーが表示されます。ただし、問題は、添付された画像が失われ、ユーザーがもう一度選択する必要があることです。これは、cached_attachment_dataと呼ばれるさらに別のプラグインを使用して非常に簡単に修正できます:
models / image_uploader.rb
plugin :cached_attachment_data
次に、フォームに非表示のフィールドを追加するだけです。
views / photos / _form.html.erb
<%= f.hidden_field :image, value: @photo.cached_image_data %> <%= f.label :image %> <%= f.file_field :image %>
写真の編集
これで画像をアップロードできますが、編集する方法がないので、すぐに修正しましょう。対応するコントローラーのアクションはやや些細なものです:
photos_controller.rb
def edit @photo = Photo.find(params[:id]) end def update @photo = Photo.find(params[:id]) if @photo.update_attributes(photo_params) flash[:success] = 'Photo edited!' redirect_to photos_path else render 'edit' end end
同じ_form
部分的に利用されます:
views / photos / edit.html.erb
<h1>Edit Photo</h1> <%= render 'form' %>
いいですが、十分ではありません。ユーザーはアップロードされた画像を削除できません。これを可能にするために、別のプラグインが必要になります-何を推測しますか-
models / image_uploader.rb
plugin :remove_attachment
:remove_image
という仮想属性を使用します 、コントローラー内で許可します:
photos_controller.rb
def photo_params params.require(:photo).permit(:title, :image, :remove_image) end
レコードに添付ファイルがある場合は、チェックボックスを表示して画像を削除します。
views / photos / _form.html.erb
<% if @photo.image_data? %> Remove attachment: <%= f.check_box :remove_image %> <% end %>
サムネイル画像の生成
現在、元の画像を表示していますが、これはプレビューに最適な方法ではありません。写真が大きく、スペースを占有しすぎる可能性があります。もちろん、CSSの width
を使用することもできます。 およびheight
属性ですが、それも悪い考えです。ご覧のとおり、スタイルを使用して画像を小さく設定した場合でも、ユーザーは元のファイルをダウンロードする必要があり、かなり大きくなる可能性があります。
したがって、最初のアップロード時にサーバー側で小さなプレビュー画像を生成することをお勧めします。これには、2つのプラグインと2つの追加のgemが含まれます。まず、宝石をドロップします:
gem "image_processing" gem "mini_magick", ">= 4.3.5"
Image_processingは、神社の作者によって作成された特別な宝石です。画像を操作するための高レベルのヘルパーメソッドをいくつか紹介します。このgemは、ImageMagickのRubyラッパーであるmini_magickに依存しています。ご想像のとおり、このデモを実行するには、システムにImageMagickが必要です。
これらの新しいgemをインストールします:
bundle install
次に、プラグインとその依存関係を含めます。
models / image_uploader.rb
require "image_processing/mini_magick" class ImageUploader < Shrine include ImageProcessing::MiniMagick plugin :processing plugin :versions # other code... end
処理は、画像を操作できるようにするプラグインです(たとえば、画像を縮小、回転、別の形式に変換するなど)。次に、バージョンを使用すると、さまざまなバリエーションのイメージを作成できます。このデモでは、「original」と「thumb」( 300x300
にサイズ変更)の2つのバージョンが保存されます。 。
画像を処理してその2つのバージョンを保存するコードは次のとおりです。
models / image_uploader.rb
class ImageUploader < Shrine process(:store) do |io, context| { original: io, thumb: resize_to_limit!(io.download, 300, 300) } end end
resize_to_limit!
image_processinggemによって提供されるメソッドです。画像を300x300
に縮小するだけです 大きい場合は何もせず、小さい場合は何もしません。さらに、元のアスペクト比を維持します。
これで、画像を表示するときに、:original
のいずれかを指定する必要があります。 または:thumb
image_url
への引数 方法:
views / photos / _photo.html.erb
<div> <% if photo.image_data? %> <%= image_tag photo.image_url(:thumb) %> <% end %> <p><%= photo.title %> | <%= link_to 'Edit', edit_photo_path(photo) %></p> </div>
フォーム内でも同じことができます:
views / photos / _form.html.erb
<% if @photo.image_data? %> <%= image_tag @photo.image_url(:thumb) %> Remove attachment: <%= f.check_box :remove_image %> <% end %>
アップロードの完了後に処理済みファイルを自動的に削除するには、delete_raw:
というプラグインを追加します。models / image_uploader.rb
plugin :delete_raw
画像のメタデータ
実際に画像をレンダリングする以外に、そのメタデータを取得することもできます。たとえば、元の写真のサイズとMIMEタイプを表示してみましょう。
views / photos / _photo.html.erb
<div> <% if photo.image_data? %> <%= image_tag photo.image_url(:thumb) %> <p> Size <%= photo.image[:original].size %> bytes<br> MIME type <%= photo.image[:original].mime_type %><br> </p> <% end %> <p><%= photo.title %> | <%= link_to 'Edit', edit_photo_path(photo) %></p> </div>
その寸法はどうですか?残念ながら、デフォルトでは保存されませんが、これはstore_dimensionsというプラグインで可能です。
画像のサイズ
store_dimensionsプラグインはfastimagegemに依存しているため、今すぐ接続してください:
gem 'fastimage'
実行することを忘れないでください:
bundle install
プラグインを含めるだけです:
models / image_uploader.rb
plugin :store_dimensions
そして、 width
を使用して寸法を表示します およびheight
メソッド:
views / photos / _photo.html.erb
<div> <% if photo.image_data? %> <%= image_tag photo.image_url(:thumb) %> <p> Size <%= photo.image[:original].size %> bytes<br> MIME type <%= photo.image[:original].mime_type %><br> Dimensions <%= "#{photo.image[:original].width}x#{photo.image[:original].height}" %> </p> <% end %> <p><%= photo.title %> | <%= link_to 'Edit', edit_photo_path(photo) %></p> </div>
また、寸法コード>があります 幅と高さを含む配列を返す使用可能なメソッド(たとえば、
[500、750]
。
クラウドへの移行
開発者はアップロードされたファイルをホストするためにクラウドサービスを選択することが多く、Shrineはそのような可能性を示しています。このセクションでは、AmazonS3にファイルをアップロードする方法を紹介します。
最初のステップとして、さらに2つのgemを Gemfileに含めます。 :
gem "aws-sdk", "~> 2.1" group :development do gem 'dotenv-rails' end
S3のSDKを使用するにはaws-sdkが必要ですが、dotenv-railsは開発中の環境変数を管理するために使用されます。
bundle install
先に進む前に、APIを介してS3にアクセスするためのキーペアを取得する必要があります。取得するには、Amazon Web Services Consoleにサインイン(またはサインアップ)して、セキュリティクレデンシャル>ユーザーに移動します。 。 S3でファイルを操作する権限を持つユーザーを作成します。 S3へのフルアクセスを提示する簡単なポリシーは次のとおりです:
{ "Version": "2016-11-14", "Statement": [ { "Effect": "Allow", "Action": "s3:*", "Resource": "*" } ] }
作成したユーザーのキーペアをダウンロードします。または、ルートアクセスキーを使用することもできますが、強くお勧めしません 非常に安全ではないので、そうすることはできません。
次に、ファイルをホストするS3バケットを作成し、プロジェクトのルートにファイルを追加して構成をホストします。
.env
S3_KEY=YOUR_KEY S3_SECRET=YOUR_SECRET S3_BUCKET=YOUR_BUCKET S3_REGION=YOUR_REGION
絶対に公開しないでください このファイルを公開し、Gitから除外するようにしてください:
.gitignore
.env
次に、Shrineのグローバル構成を変更し、新しいストレージを導入します。
config / initializers / shrine.rb
require "shrine" require "shrine/storage/s3" s3_options = { access_key_id: ENV['S3_KEY'], secret_access_key: ENV['S3_SECRET'], region: ENV['S3_REGION'], bucket: ENV['S3_BUCKET'], } Shrine.storages = { cache: Shrine::Storage::FileSystem.new("public", prefix: "uploads/cache"), store: Shrine::Storage::S3.new(prefix: "store", **s3_options), }
それでおしまい!アプリの他の部分に変更を加える必要はなく、この新しいストレージをすぐにテストできます。間違ったキーに関連するS3からエラーを受け取った場合は、末尾のスペースや非表示の特殊記号を使用せずに、キーとシークレットを正確にコピーしたことを確認してください。
結論
この記事は終わりです。うまくいけば、今ではあなたは神社を使用することに非常に自信を持っており、あなたのプロジェクトの1つでそれを使用することを熱望しています。このgemの機能の多くについて説明しましたが、ファイルとともに追加のコンテキストを保存する機能や直接アップロードメカニズムなど、さらに多くの機能があります。
したがって、Shrineのドキュメントと、利用可能なすべてのプラグインについて詳しく説明している公式Webサイトを参照してください。この宝石について他に質問がある場合は、遠慮なく投稿してください。一緒にいてくれてありがとう、また会いましょう!
-
RailsでのTailwindCSSの使用
CSSは魔法のようですが、時間がかかります。美しく、機能的で、アクセスしやすいサイトを使用するのは楽しいことですが、独自のCSSを作成するのは大変です。 Bootstrapなどの多くのCSSライブラリは近年爆発的に増加しており、Tailwindは2021年にパックをリードしています。 RailsにはTailwindが付属していませんが、この記事では、TailwindCSSを新しいRubyon Railsプロジェクトに追加する方法を説明します。これにより、設計の実装にかかる時間を節約できます。また、Tailwindのユーティリティクラスを使用した設計のウォークスルーも行います。このチュートリア
-
Rails5でのAngularの使用
あなたは前にその話を聞いたことがあります。分散型で完全に機能するバックエンドAPIと、通常のツールセットで作成されたフロントエンドで実行されているアプリケーションがすでにあります。 次に、Angularに移動します。または、AngularをRailsプロジェクトと統合する方法を探しているだけかもしれません。これは、この方法を好むためです。私たちはあなたを責めません。 このようなアプローチを使用すると、両方の世界を活用して、たとえばRailsとAngularのどちらの機能を使用してフォーマットするかを決定できます。 構築するもの 心配する必要はありません。このチュートリアルは、この目的のた