画像投稿機能を実装する方法（Rails・初心者向け）

ポートフォリオを作成する際にユーザーが画像を投稿する機能を実装したので、アウトプットを兼ねて簡単にまとめてみました。
#目次
①セットアップ
　(1)Active Storageをインストールする
　(2)Active Storageを利用することを宣言する
　(3)ファイルをローカルに保存する
②ファイルをレコードに添付する
　(1)各レコードに1つのファイルを添付する場合（has_one_attached）
　(2)各レコードに複数のファイルを添付する場合（has_many_attached）
③Contorollerの開発
④Viewの開発
⑤画像を変換し、ファイルの大きさを調整する
　(1)バリアントを有効にする
　(2)画像の大きさを指定する
⑥画像が表示されない時の対処法（ImageMagickのインストール）
おわりに
参照元
##①セットアップ
####(1)Active Storageをインストールする
Active Storageとは、ファイルをアップロードやアタッチをするための機能です。Active Storageをインストールして、マイグレーションも実行します。

```
$ rails active_storage:install
```
```
$ rails db:migrate
```
####(2)Active Storageを利用することを宣言する
configのstorage.ymlにActive Storageを使うことを宣言します。storage.ymlがない場合はご自身でファイルを作成してください。

```yml:config/storage.yml
local:
  service: Disk
  root: <%= Rails.root.join("storage") %>

test:
  service: Disk
  root: <%= Rails.root.join("tmp/storage") %>

amazon:
  service: S3
  access_key_id: ""
  secret_access_key: ""
```
`local`、`test`、`amazon`の3つのテーブルを宣言しています。
####(3)ファイルをローカルに保存する

```ruby:config/environments/development.rb
config.active_storage.service = :local
```
##②ファイルをレコードに添付する
各レコードに1つファイルを添付するのか、複数添付するのかで記述が少し変わってきます。アプリケーションにMessageモデルがあるとして考えてみましょう。
####(1)各レコードに1つのファイルを添付する場合（has_one_attached）
has_one_attachedを使用することで、レコードとファイルの間に1対1の関係を設定することができます。各メッセージに1つのimageを持たせるために、次のようにMessageモデルを定義します。

```Ruby:app/models/message.rb
class Message < ApplicationRecord
  has_one_attached :image
end
```
images.attachを呼び出すと、既存のメッセージに新しい画像を追加できます。

```Ruby
@message.image.attach(params[:image])
```
image.attached?で特定のmessageがimageを持っているかどうかを調べられます。

```Ruby
@message.image.attached?
```
####(2)各レコードに複数のファイルを添付する場合（has_many_attached）
has_many_attachedを使用することで、レコードとファイルの間に1対多の関係を設定します。各レコードに複数の添付ファイルをアタッチできます。メッセージごとに多数の画像を持たせるために、次のようにMessageモデルを定義します。

```Ruby:app/models/message.rb
class Message < ApplicationRecord
  has_many_attached :images
end
```
images.attachを呼び出すと、既存のメッセージに新しい画像を追加できます。

```Ruby
@message.images.attach(params[:images])
```
image.attached?で特定のmessageがimageを持っているかどうかを調べられます。

```Ruby
@message.images.attached?
```
##③Contorollerの開発
controllerを編集します。ストロングパラメーターに:imageカラムを追加します。has_one_attachedを使用した場合について考えてみます。

```Ruby:app/contorollers/messages_contoroller.rb
class MessagesController < ApplicationController

# Strong Parameter
  private
    def message_params
      params.require(:message).permit(:title, :content, :image)
    end
end
```
##④Viewの開発
viewを編集します。こちらでも同様にhas_one_attachedを使用した場合について考えてみます。

```erb:app/views/messages/new.html.erb
<%= form_with model: @message, local: true do |f| %>

  <div class="form-group">
    <label>タイトル</label>
    <%= f.text_field :title, class: "form-control" %>
  </div>
  <div class="form-group">
    <label>メッセージ</label>
    <%= f.text_area :content, class: "form-control" %>
  </div>
  <div class="form-group">
    <label>画像</label>
    <%= f.file_field :image, class: "form-control" %>
  </div>
  <div class="text-center">
    <%= f.submit "送信", class: "btn btn-primary" %>
  </div>
<% end %>
```

```erb:app/views/messages/index.html.erb
<h1>メッセージ一覧</h1>

<ul>
  <% @messages.each do |message| %>
    <li><%= message.tilte %></li>
    <li><%= message.content %></li>
    <li>
      <% if message.image.attached? %>
        <%= image_tag message.image %>
      <% end %>
    </li>
  <% end %>
</ul>
```
この状態で一度プレビューで確認してみてください。indexのページで画像は表示されたでしょうか？表示されない場合は、振り返って間違いがないかどうか確認してみてください。
##⑤画像を変換し、ファイルの大きさを調整する
先ほどプレビューで画像をご覧になったかと思いますが、ファイルが大きすぎたり小さすぎたりしませんでしたか？これから画像を任意の大きさに調整する方法について解説していきます。
####(1)バリアントを有効にする
`image_processing` gemをGemfileに追加し、インストールします。

```
gem 'image_processing', '~> 1.2'
```
```
$ bundle install
```
####(2)画像の大きさを指定する
バリアントが有効になったので、画像の大きさを調整できるようになりました。画像を任意の大きさに変えてみましょう。

```erb:app/views/messages/index.html.erb
<%= image_tag tech.image.variant(resize: "160x107") %>
```
引数の数字を変えると画像の大きさが変わります。
#⑥画像が表示されない時の対処法（ImageMagickのインストール）
`image_processing` gemをインストールし、.variant(resize: "〇〇x〇〇")で大きさを指定したのにも関わらず、画像が正常に表示されない方はログを確認してください。`MiniMagick::Error (You must have ImageMagick or GraphicsMagick installed):`や`MiniMagick::Invalid (You must have ImageMagick or GraphicsMagick installed):`などの記述があるかと思います。この場合、ImageMagickがインストールされていないので、これをインストールする必要があります。以下のコマンドで実行してください。

```
$ sudo apt-get install imagemagick
```
`sudo: apt-get: command not found`とエラーになった場合は、次のコマンドを実行してください。

```
$ sudo yum install -y ImageMagick
```
もしこれでもうまくいかない場合は、apt-getをアップデートします。

```
$ sudo apt-get update
```
上記のどれかでインストールできたかと思います。それでは改めてプレビューで確認してみましょう。
#おわりに
画像投稿機能を実装できましたでしょうか？初めての投稿なので、分かりにくい点や説明不足なところがあったらすみません。少しでも参考になれば幸いです。
#参照元
[Railsガイド Active Storage](https://railsguides.jp/active_storage_overview.html)
[Rails Tutorial 13章で Cloud9 に ImageMagick をインストールできずに少し困った話](https://qiita.com/fuu-sh/items/5ae8afe1c19b44e99523#tldr)