3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【初心者】Active Storageについて

Last updated at Posted at 2020-11-06

はじめに

プログラミング学習を初めて3ヶ月程度の初心者ですが、Railsチュートリアルで学んだことを備忘録として残したいと思います。この記事は、Railsチュートリアルを参考に書きました。

Active Storageとは

Railsでファイルをアップロードするのに最も便利な方法は、Railsに組み込まれているActive Storageという機能を用いることです。これを使えば、フォームで画像の投稿機能などが簡単に作れます。
アプリケーションでActive Storageを用いることで、ImageMagickで画像のアップロードを変換したり、 PDFやビデオなどの非画像アップロードの画像表現を生成したり、任意のファイルからメタデータを抽出したりできます。

Active Storageを使えるようにする

$ rails active_storage:install
$ rails db:migrate

このマイグレーションにより、active_storage_blobsactive_storage_attachmentsという名前の2つのテーブルが生成される。`active_storage_blobsは実際にアップロードしたファイルが保存されるテーブルで、active_storage_attachments`は中間テーブルになります。

1つのファイルを追加する

今回は、Micropostモデルに1つの画像を追加したとします。

micropost.rb
class Micropost < ApplicationRecord
 has_one_attached :image
end

:imageはファイル名で、:photo、:avatarなど、ファイルの用途に合わせて好きなものをして下さい。
has_one_attachedメソッドは、指定のモデルと、アップロードされたファイルを関連付けるのに使います。この場合はimageを指定してMicropostモデルと関連付けます。

次に、マイクロポストのフォームにfile_fieleタグを追加します。

app/views/shared/_micropost_form.html.erb
<%= form_with model: @micropost, local: true  do |f| %>
  <%= f.text_area :content %>
  <%= f.file_field :image %>
  <%= f.submit %>
<% end %>

最後に、Micropostsコントローラを更新して、新たに作成したmicropostオブジェクトに画像を追加できるようにします。Actuve Storage APIにはそのためのattachメソッドが提供されていますので、これを使って行えます。具体的には、Micropostsコントローラのcreateアクションの中で、アップロードされた画像を@micropostオブジェクトにアタッチします。このアップロードを許可するために、micropost_paramsメソッドを更新して:imageを許可済み属性リストに追加し、Web経由で更新できるようにする必要もあります。

microposts_controller.rb
class MicropostsController < ApplicationController
 def create
    @micropost = current_user.microposts.build(micropost_params)
    @micropost.image.attach(params[:micropost][:image])
    if @micropost.save
      flash[:success] = "Micropost created!"
      redirect_to root_url
    else
      @feed_items = current_user.feed.paginate(page: params[:page])
      render 'static_pages/home'
    end
  end

  private

    def micropost_params
      params.require(:micropost).permit(:content, :image)
    end
 end

一度画像がアップロードされれば、micropostパーシャルのimage_tagヘルパーを用いて、関連付けられたmicropost.imageを描画(レンダリング)できるようになります。また、投稿は画像を添付されていたり(画像の無いテキストのみ等)、されていなかったりするため、attached?という論理値を返すメソッドを使って、画像が添付されている投稿なのか、添付されていない投稿かを調べ、画像が添付されていたら、画像を表示するようにします。

app/views/microposts/_micropost.html.erb
 <%= image_tag micropost.image if micropost.image.attached? %>

画像の検証

上記のアップローダーには、いくつかの目立つ欠点があります。特に、アップロードされた画像に対する制限がないため、もしユーザーが巨大なファイルを上げたり、無効なファイルを上げると問題が発生してしまいます。この欠点を直すために、画像サイズやフォーマットに対するバリデーションを実装します。
Active Storageは、こうしたフォーマット機能やバリデーション機能がネイティブでサポートされていません。なのでActive Storageバリデーション用のgemを追加します。

Gemfile
gem 'active_storage_validations'

忘れずに、bundle installを実行します。

$ bundle install

このgemのドキュメントを読んでみると、次のようにcontent_typeを検査することで画像をバリデーションできることがわかります。

content_type: { in: %w[image/jpeg image/gif image/png],
                message: "must be a valid image format" }

これにより、サポートする画像フォーマットに対応する画像をチェックします。

同様に、ファイルサイズも以下のようにバリデーションできます。

size: { less_than: 5.megabytes,
        message: "should be less than 5MB" }

今回は、画像のサイズを5MBに制限します。
これらのバリデーションをMicropostモデルに追加します。

micropost.rb
class Micropost < ApplicationRecord
 validates :image,   content_type: { in: %w[image/jpeg image/gif image/png],
                                      message: "must be a valid image format" },
                      size:         { less_than: 5.megabytes,
                                      message: "should be less than 5MB" }
end

また、これらのバリーデーションに加え、クライアント側(つまりブラウザ)にも、画像アップロードのサイズやフォーマットをチェックする仕組みを追加します。JavaScript(具体的にはjQuery)をちょっぴり加えて、ユーザーがアップロードしようとする画像が巨大過ぎるときにアラートを表示してみましょう(こうしておけばユーザーがアップロードで無駄な時間を使わずに済みますし、サーバーの負荷も軽くなります)。

app/views/shared/_micropost_form.html.erb
<script type="text/javascript">
  $("#micropost_image").bind("change", function() {
    var size_in_megabytes = this.files[0].size/1024/1024;
    if (size_in_megabytes > 5) {
      alert("Maximum file size is 5MB. Please choose a smaller file.");
      $("#micropost_image").val("");
    }
  });
</script>

これにより、もしファイルサイズが大きすぎた場合、alertメソッドで警告を出します。

最後に、acceptパラメータをfile_field入力タグで用いれば、有効なフォーマットでないとアップロードできないことをユーザーに伝えられるようになります。

app/views/shared/_micropost_form.html.erb
<%= f.file_field :image, accept: "image/jpeg,image/gif,image/png" %>

最初に有効な画像フォーマットだけを選択可能にしておき、それ以外のファイルタイプを灰色で表示します。

画像のリサイズ

画像をリサイズするためには、画像を操作するプログラムが必要になります。今回はImageMagickというプログラムを使うので、これを開発環境にインストールします。(本番環境がHerokuであれば、既に本番環境で`ImageMagickが使えるようになっています。)

クラウドIDEでは、次のコマンドでこのプログラムをインストールできます。

$ sudo apt-get -y install imagemagick

クラウドIDEや同等のLinux環境を使っていない場合、それぞれの環境に応じてImagiMagickをインストールする手順が変わります。例えばMacの場合であれば、Homebrewを導入しておかないとbrew install imagemagickコマンドでインストールできません。

Homebrewの場合のインストール方法

$ brew install imagemagick

次は、画像処理のためにいくつかのgemが必要です。
image_processing gemや、Ruby製ImageMagickプロセッサであるmini_magick gemなどを必要とします。

Gemfile
gem 'image_processing'
gem 'mini_magick'
$ bundle install

おそらく、インストール後にRailsサーバーの再起動が必要になると思います。

variatメソッド

Active Storageが提供するvariantメソッドで変換済み画像を作成できるようになります。特にresize_to_limitオプションを用いて、以下のように画像の幅や高さが500ピクセルを超えることのないように制約をかけます。

image.variant(resize_to_limit: [500, 500])

このコードは別途display_imageメソッドに置いて利便性を高めておきます。

micropost.rb
# 表示用のリサイズ済み画像を返す
def display_image
 imge.variant(resize_to_limit: [500, 500])
end

これでdisplay_imageをmicropostパーシャルで使えるようになります。

app/views/microposts/_micropost.html.erb
<%= image_tag micropost.display_image if micropost.image.attached? %>
3
3
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
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?