Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

RailsとCarrierWaveを使ったファイルアップロードの実装ガイド

本記事は「Railsでのアップロード」シリーズの1つです。今回は、Rails向けファイルアップロードソリューションとして最も人気のあるCarrierWaveを紹介します。CarrierWaveは導入が非常に簡単で、標準で豊富な機能を備えている点が魅力です。さらにコミュニティによって多数のノウハウ記事が公開されているため、迷うことなく開発を進められます。

この記事では、以下の内容を学ぶことができます。

  • RailsアプリへのCarrierWaveの組み込み
  • バリデーションの追加
  • リクエスト間でのファイル保持
  • ファイルの削除
  • サムネイル画像の生成
  • リモートURLからのファイルアップロード
  • 複数ファイルアップロードへの対応
  • クラウドストレージの利用

本記事のソースコードはGitHubで公開しています。それでは始めましょう!

基盤となるアプリケーションの作成

まずは、いつものように新しいRailsアプリケーションを作成します。

このデモではRails 5.0.2を使用します。なお、CarrierWave 1系はRails 4以降とRuby 2以降にのみ対応している点に注意してください。まだRails 3を使っている場合は、CarrierWave 0.11をインストールする必要があります。

CarrierWaveの動作を確認するため、Postモデルだけを持つシンプルなブログアプリケーションを作成します。主な属性は以下の通りです。

  • title(string)
  • body(text)
  • image(string)—投稿に添付される画像(正確にはファイル名)を格納するフィールドです

マイグレーションを生成して適用しましょう。

続いてルーティングを設定します。

config/routes.rb

そして、基本的なコントローラーを作成します。

posts_controller.rb

次に一覧画面(index)のビューを作成します。

views/posts/index.html.erb

対応するパーシャルも用意します。

views/posts/_post.html.erb

ここではRailsのtruncateメソッドを使い、本文の先頭150文字のみを表示しています。他のビューとフォームパーシャルを作成する前に、まずはCarrierWaveをアプリに組み込みましょう。

CarrierWaveの組み込み

Gemfileにgemを追加します。

Gemfile

以下のコマンドを実行します。

CarrierWaveの設定は「アップローダー」と呼ばれるファイル内に記述し、それをモデルに組み込みます。アップローダーを生成するには、次のコマンドを使用します。

app/uploadersディレクトリにimage_uploader.rbというファイルが生成されます。このファイルには便利なコメントやサンプルコードが含まれているので、参考にするとよいでしょう。本デモではActiveRecordを使用しますが、CarrierWaveはMongoid、Sequel、DataMapperにも対応しています。

次に、このアップローダーをモデルにマウント(include)します。

models/post.rb

アップローダーにはすでに妥当なデフォルト設定が含まれていますが、少なくともアップロードされたファイルの保存先は指定する必要があります。ここではまずファイルストレージを採用しましょう。

uploaders/image_uploader.rb

デフォルトでは、ファイルはpublic/uploadsディレクトリに保存されます。そのため、バージョン管理システムから除外しておくのがおすすめです。

.gitignore

アップローダー内のstore_dirメソッドを変更すれば、別の場所に保存することも可能です。

これで準備が整いました。新しいビューとフォームパーシャルを作成して、ファイルのアップロードを開始できるようにしましょう。

views/posts/new.html.erb

views/posts/_form.html.erb

image属性はすでに許可済みなので、PostsControllerを変更する必要はありません。

最後に編集画面を作成します。

views/posts/edit.html.erb

これで完了です!サーバーを起動して、画像付きの投稿を作成してみてください。ただし、現状では画像がどこにも表示されないので、次のセクションで詳細ページを追加しましょう。

画像の表示

まだ作成していないビューはshowだけです。追加しましょう。

views/posts/show.html.erb

ご覧の通り、添付ファイルの表示はとても簡単です。@post.image.urlと書くだけで画像のURLを取得できます。ファイルへのパスが必要な場合はcurrent_pathメソッドを使用します。また、CarrierWaveは添付ファイルの有無を確認するためのimage?メソッドも提供しています(ファイルが存在しなくてもimageメソッド自体は決してnilを返さない点に注意してください)。

これで投稿ページにアクセスすると画像が表示されますが、サイズ制限をかけていないため、画像が大きすぎる可能性があります。CSSで縮小表示することもできますが、アップロード後にサムネイルを生成する方がはるかに効率的です。これにはいくつか追加の手順が必要になります。

サムネイルの生成

画像の切り抜きやリサイズを行うには、専用のツールが必要です。CarrierWaveは標準でRMagickとMiniMagickというgemに対応しており、これらはImageMagickを通じて画像を操作します。ImageMagickは既存画像の編集や新規画像の生成を可能にするオープンソースソフトウェアなので、先に進む前にダウンロードしてインストールしておきましょう。その後、2つのgemのどちらかを選択します。ここではインストールが簡単でサポートも充実しているMiniMagickを採用します。

Gemfile

以下を実行します。

次に、MiniMagickをアップローダーに組み込みます。

uploaders/image_uploader.rb

あとは、アップローダーに新しい「バージョン」を定義するだけです。「バージョン」(スタイルとも呼ばれます)の概念は多くのファイルアップロードライブラリで採用されており、元の添付ファイルをもとに、異なるサイズや形式の追加ファイルを生成することを意味します。ここではthumbというバージョンを定義してみましょう。

uploaders/image_uploader.rb

バージョンは好きな数だけ定義でき、しかも他のバージョンをベースにすることもできます。

uploaders/image_uploader.rb

すでに画像をアップロード済みの場合、それらにはサムネイルが存在しません。しかし心配いりません。Railsコンソールから再生成できます。

最後に、元画像へのリンク付きでサムネイルを表示しましょう。

views/posts/show.html.erb

サーバーを起動して結果を確認してみてください!

バリデーションの追加

現在、アップロード自体は機能していますが、ユーザーの入力に対するバリデーションがまったくありません。これは明らかに問題です。画像のみを扱いたいので、.png、.jpg、.gifの拡張子をホワイトリストとして許可しましょう。

uploaders/image_uploader.rb

content_type_whitelistメソッドを定義すれば、コンテンツタイプのチェックも追加できます。

uploaders/image_uploader.rb

逆に、実行ファイルなど特定の種類のファイルを拒否したい場合は、content_type_blacklistメソッドでブラックリスト方式を取ることも可能です。

ファイルの種類と拡張子のチェックに加えて、ファイルサイズを1MB未満に制限しましょう。そのために、ActiveModel向けのファイルバリデーションを提供する追加のgemが必要です。

Gemfile

インストールします。

必要なバリデーションを追加します(titlebodyのチェックも併せて追加しています)。

models/post.rb

次に、CarrierWaveのエラーメッセージに対するI18n翻訳を追加します。

config/locales/en.yml

現状ではバリデーションエラーがどこにも表示されないので、共有パーシャルを作成しましょう。

views/shared/_errors.html.erb

このパーシャルをフォーム内で使用します。

views/posts/_form.html.erb

不正なファイルをアップロードして挙動を確認してみてください。正常に動作するはずですが、有効なファイルを選んだ状態でタイトルや本文を空のまま送信すると、チェックに失敗してエラーが表示されます。ところが、このときファイルフィールドがクリアされてしまい、ユーザーはもう一度画像を選び直さなければなりません。これはあまり使い勝手がよくありません。この問題を解決するには、フォームにもう1つフィールドを追加する必要があります。

リクエスト間でのファイル保持

フォーム再表示時のファイル保持は、実はとても簡単に実現できます。隠しフィールド(hidden field)を新しく追加し、コントローラーでその属性を許可するだけです。

views/shared/_form.html.erb

posts_controller.rb

これでimage_cacheが自動的に設定され、画像が失われなくなります。加えてサムネイルを表示しておくと、画像が正常に処理されたことをユーザーが視覚的に確認できるので便利です。

views/shared/_form.html.erb

画像の削除

レコード編集時に添付ファイルを削除できる機能も、非常によく使われます。CarrierWaveならこの機能も簡単に実装できます。フォームに新しいチェックボックスを追加しましょう。

views/shared/_form.html.erb

そしてremove_image属性を許可します。

posts_controller.rb

これで完成です!手動で画像を削除したい場合は、remove_image!メソッドを使用します。

リモートURLからのアップロード

CarrierWaveには、URLを指定してリモートのファイルをアップロードできる優れた機能が標準で備わっています。新しいテキストフィールドを追加し、対応する属性を許可するだけで、この機能を利用できます。

views/shared/_form.html.erb

posts_controller.rb

なんと便利な機能でしょう。その他のコード変更は一切不要で、すぐにこの機能を試せます!

複数ファイルアップロードへの対応

投稿に複数の添付ファイルを持たせたい場合を考えてみましょう。現在の構成では不可能ですが、幸いCarrierWaveはこのようなケースにも対応しています。この機能を実装するには、シリアライズ型フィールド(SQLiteの場合)またはJSON型フィールド(PostgresやMySQLの場合)を追加する必要があります。ここでは後者を採用するため、データベースアダプターを変更しましょう。Gemfileからsqlite3 gemを削除し、代わりにpgを追加します。

Gemfile

インストールします。

データベース設定を以下のように変更します。

config/database.yml

対応するPostgresデータベースを作成したら、マイグレーションを生成して適用します。

SQLiteを使い続けたい場合は、CarrierWaveの公式ドキュメントに記載の手順に従ってください。

次に、アップローダーをマウントします(複数形になっている点に注目してください!)。

model/post.rb

ここでは添付ファイルにも同じアップローダーを使用していますが、もちろん異なる設定を持つ新しいアップローダーを生成しても問題ありません。

フォームに複数ファイル選択フィールドを追加します。

views/shared/_form.html.erb

attachmentsフィールドは配列を格納するため、コントローラーでは次のように許可します。

posts_controller.rb

最後に、投稿の添付ファイルを反復処理して、通常どおり表示できます。

views/shared/show.html.erb

各添付ファイルには、ImageUploaderで設定したとおりサムネイルが自動的に生成されます。素晴らしいですね!

クラウドストレージの利用

ファイルストレージを使い続けることが常に望ましいとは限りません。たとえばHerokuではカスタムファイルを保存できないためです。そこで「CarrierWaveとAmazon S3クラウドストレージを連携させるにはどうすればいいのか?」という疑問が生じます。実は、これも非常に簡単な作業です。CarrierWaveはfog-aws gemに依存してこの機能を実現しています。

Gemfile

インストールします。

CarrierWave用のイニシャライザを作成し、クラウドストレージをグローバルに設定しましょう。

config/initializers/carrierwave.rb

その他にも利用可能なオプションがあります。詳しくはドキュメントを参照してください。

ここではdotenv-rails gemを使って環境変数を安全に設定していますが、他の方法を選んでも構いません。ただし、S3のキーペアが公開されないよう必ず注意してください。公開されてしまうと、誰でもあなたのバケットに何でもアップロードできてしまいます!

次に、storage :fileの行を以下に置き換えます。

uploaders/image_uploader.rb

S3以外にも、CarrierWaveはGoogle StorageやRackspaceへのアップロードに対応しています。これらのサービスも簡単にセットアップできます。

まとめ

今回は以上です!CarrierWaveの主要な機能をすべて網羅しました。これであなたのプロジェクトでも活用できるはずです。さらに追加のオプションも用意されているので、ぜひドキュメントを一読してみてください。

もし行き詰まったら、遠慮なく質問を投稿してください。また、CarrierWaveのWikiには多くの一般的な疑問に答える役立つノウハウ記事が掲載されているので、覗いてみる価値があります。

最後までお読みいただきありがとうございました。Happy Coding!


  1. Vue、Vuex、Railsを使用したフルスタックアプリケーションの構築

    スケーラビリティを念頭に置いてフルスタックアプリケーションを構築することは、特に、完全なタイプスクリプトをサポートする最新バージョンのVueおよびVuexを使用して構築する場合、威圧的になる可能性があります。この記事では、不健康な家畜への治療の処方を管理するCRUDアプリケーションを探索することで、APIリクエストとデータベースの相互作用を処理するVuex4.0を使用した状態管理からスケーラブルなフルスタックアプリケーションを構築するために知っておく必要のあるすべてを読者に教えます。バックエンドはRailsで構築され、フロントエンドによる統合のために基本的なCRUDAPIを公開します。 ほと

  2. Rails5でのAngularの使用

    あなたは前にその話を聞いたことがあります。分散型で完全に機能するバックエンドAPIと、通常のツールセットで作成されたフロントエンドで実行されているアプリケーションがすでにあります。 次に、Angularに移動します。または、AngularをRailsプロジェクトと統合する方法を探しているだけかもしれません。これは、この方法を好むためです。私たちはあなたを責めません。 このようなアプローチを使用すると、両方の世界を活用して、たとえばRailsとAngularのどちらの機能を使用してフォーマットするかを決定できます。 構築するもの 心配する必要はありません。このチュートリアルは、この目的のた