Ruby on RailsでActive Storageを使って画像投稿機能を実装する方法

※2022年から技術系の記事は[個人ブログ](https://yamaday0u.net/category/programmer/)に投稿しております。ぜひこちらもご覧ください→[yamaday0u Blog](https://yamaday0u.net/category/programmer/)

Ruby on Railsで画像投稿機能を実装する方法はたくさんあると思います。
この記事では未経験からのエンジニア転職を目指しているプログラミング初学者である私が、おそらく最も一般的な手法と思われるActive Storageを用いた実装方法をまとめました。

# #Active StorageとImageMagick
今回の画像投稿機能は、画像をアップロードする機能と、画像を加工（サイズを変更したり保存形式を変更したり）する機能があります。

前者はActive Storageを、後者はImageMagickを使って実装します。

### Active Storageとは
Rails5.2で追加された、ファイルアップロード機能を簡単に実装できるgemです。
元々はインストールが必要なgemでしたが、Railsに統合されたそうです。

### ImageMagickとは
コマンドラインから画像の処理を加えることができるソフトウェアです。
このソフトウェアをRailsで使用するためにMiniMagickというgemを導入します。
またImageProcessingというgemを導入することで画像サイズを調整する機能も実装できます。

|gem|機能|
|:--|:--|
|MiniMagick|ImageMagickの機能をRailsで扱えるようにする|
|ImageProcessing|MiniMagickでは提供できない、画像サイズを調整する機能を提供する|

いくつか紹介しましたが、今回の記事ではActive Storageのみを扱います。
MiniMagickやImageProcessingは、今後この記事に追記するか別の記事にするかでまとめたいと思います。

## Active Storageの使用準備
ターミナル上で画像投稿機能を実装したいアプリのディレクトリに移動し、下記のコマンドを入力します。

```:ターミナル
rails active_storage:install
rails db:migrate
```
`rails active_storage:install`でActive Storageがインストールされ、マイグレーションファイルも生成されるので、`rails db:migrate`でマイグレートしています。

このマイグレートによって、`active_storage_blobs`と`active_storage_attachments`という名前のテーブルが2つ生成されます。これらのテーブルについて説明している分かりやすい記事があったので引用します。

>これらのテーブルはBlobとAttachmentの2つのモデルが使います。Blobはファイル名、ファイルの種類、バイト数、誤り検出符号などのメタデータを保持するモデルで、Attachmentモデルは、BlobオブジェクトとActive Recordオブジェクトを紐付けるための中間テーブルです。なお、Active Storageを使う際、直接BlobとAttachmentモデルに触れる必要はありません。
 [Qiita【Rails 5.2】 Active Storageの使い方](https://qiita.com/hmmrjn/items/7cc5e5348755c517458a#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E4%BF%9D%E5%AD%98%E5%85%88%E3%81%AE%E5%A4%89%E6%9B%B4)より

ちなみに`rails active_storage:install`で生成されるマイグレーションファイルは次のようなものです。

```2020XXXXXXXXXX_create_active_storage_tables.active_storage.rb
class CreateActiveStorageTables < ActiveRecord::Migration[5.2]
  def change
    create_table :active_storage_blobs do |t|
      t.string   :key,        null: false
      t.string   :filename,   null: false
      t.string   :content_type
      t.text     :metadata
      t.bigint   :byte_size,  null: false
      t.string   :checksum,   null: false
      t.datetime :created_at, null: false

      t.index [ :key ], unique: true
    end

    create_table :active_storage_attachments do |t|
      t.string     :name,     null: false
      t.references :record,   null: false, polymorphic: true, index: false
      t.references :blob,     null: false

      t.datetime :created_at, null: false

      t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true
      t.foreign_key :active_storage_blobs, column: :blob_id
    end
  end
end
```
`active_storage_blobs`と`active_storage_attachments`テーブルが作成されているのが分かります。

## 画像を保存できるようにする
先ほど作成したActive Storageのテーブルに、画像を保存するための実装を行います。

行うことは以下の2つです。
ここでは仮に、画像を保存したいテーブルをPostsテーブル（モデルがpost.rb）、コントローラーをposts_controller.rbとします。

1. Active StorageのテーブルとPostsテーブルのアソシエーションを定義
1. posts_controller.rbにて、imageカラムの保存を許可

これらを順番に実装します。

### 1. Active StorageのテーブルとPostsテーブルのアソシエーションを定義
アソシエーションの定義には`has_one_attachedメソッド`を使います。

|メソッド名|機能|
|:--|:--|
|has_one_attached|各レコードとファイルを1対1の関係で紐づける。has_one_attachedメソッドを記述したモデルの各レコードは、それぞれ1つのファイルを添付できる。|

has_one_attachedメソッドをpost.rbに以下のように記述します。

```post.rb
class Post < ApplicationRecord
  has_one_attached :image
end
```
`:image`の部分はファイル名を表し、:photoなど他のファイル名にしても構いません。

この記述により、`モデル.ファイル名`で、添付されたファイルにアクセスできるようになります（例：Post.image）。

さらに、このファイル名は、そのモデルが紐づいたフォームから送られるパラメーターのキーにもなります。

### 2. posts_controller.rbにて、imageカラムの保存を許可
以下のように記述します。

```posts_controller.rb
class PostsController < ApplicationController
  def new
    @post = Post.new
  end

  def create
    @post = Post.create(post_params)
    redirect_to root_path
  end
  
  priveate
  def post_params
    params.require(:post).permit(:image)
  end
end
```
privateメソッドの`post_params`で、premitを使って`:imageキー`の保存を許可しています。
ちなみに投稿ページは以下のように記述します。

```new.html.erb
<%= form_with model: @post, local: true  do |form| %>
  <%= form.file_field :image %>
  <%= form.submit %>
<% end %>
```

以上で画像投稿機能の実装が完了しました。
この後の工程として、投稿した画像を表示する機能の実装がありますが、今回は割愛します。
## 参考資料
[Railsガイド v6.0 Active Storageの概要](https://railsguides.jp/active_storage_overview.html#disk%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9)
[ImageMagick公式サイト](https://imagemagick.org/)
[MiniMagick公式GitHub](https://github.com/minimagick/minimagick)
[ImageProcessing公式GitHub](https://github.com/janko/image_processing)
 [Qiita【Rails 5.2】 Active Storageの使い方](https://qiita.com/hmmrjn/items/7cc5e5348755c517458a#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E4%BF%9D%E5%AD%98%E5%85%88%E3%81%AE%E5%A4%89%E6%9B%B4)