Rails の Carrierwave を使用した画像複数アップロード機能

備忘録のため記述しています。

## Carrierwave という gem の導入

[carrierwaveuploader/carrierwave](https://github.com/carrierwaveuploader/carrierwave)

Gemfile に以下を記述

```ruby
gem "carrierwave", "~> 2.0"
```

終わったらターミナルにて bi

```ruby
bundle install
```

### Uploader の作成

```ruby
bundle exec rails g uploader Images
```

下記が作成される。

```ruby
images_uploader.rb
```

アップロードされるファイルの設定を色々弄れるけど今回は見送り。

# MVC 設定

Post モデルに対して Memory というモデルで画像登録をできるようにしている

## Model

Post

```post.rb
class Post < ApplicationRecord
  has_many :memories
  accepts_nested_attributes_for :memories, allow_destroy: true
  validates :title, presence: true
end
```

accepts_nested_attributes_for :memories の設定で posts_controller 上で memories を登録できるようにしている。

Memory

```memory.rb
class Memory < ApplicationRecord
  belongs_to :post
  mount_uploader :image, ImagesUploader
end
```

mount_uploader は carrierwave の設定。これで簡単にアップロードできるようになる。

## Controller

posts_controller.rb

```posts_controller.rb
class PostsController < ApplicationController
  

  def new
    @post = Post.new
		# @post.memories.build とすることで post に紐づいた memories を保存する準備が整う
    @post_memory = @post.memories.build
  end

  def create
    post = Post.new(post_params)
    if post.save!
		# 以下は memories に保存する処理。 each 文で複数の画像を保存可能。
      params[:memories][:image].each do |image|
        post.memories.create(image: image, post_id: post.id)
      end
    end
    redirect_to root_path
  end

  private

    def post_params
      params.require(:post).permit(:title, memories_attributes: [:image]).merge(user_id: current_user.id)
    end
end
```

## View

new.html.erb

```erb
<%= form_for @post, local: true,  html: {class: "form_area"} do |f| %>
        <div class="form_area__field">
          <%= f.text_area :title, id: "post_text", placeholder: "投稿内容を入力", rows: 10%>

          <div class="form_area__image_field">
            <%= f.fields_for :memories do |m| %>
              <%= m.label :image, "画像" %>
              <%= m.file_field :image, multiple: true, name: "memories[image][]" %>
              <%= hidden_field :memories, :post_id, value: @post.id %>
            <% end %>
          </div>

          <div class="form_area__hidden_field">
            <%= hidden_field :post, :user_id, value: current_user.id %>
          </div>

          <div class="form_area__action">
            <%= f.submit "投稿", class: "form_area__action__btn" %>
          </div>

        </div>
      <% end %>
```

fields_for で1回の投稿で複数のクラスを保存できる。

multiple: true で複数の画像を投稿できるように設定している。

### 表示するには？

```erb

<% @post.memories.each do |m|%>
     <%= image_tag m.image.url %>
<% end %>
```

上記で表示できる。

## 画像を追加するには？ (2021年1月16日追記)
既に画像つきで投稿されている記事に対して画像を追加する機能を実装しました。
結果としてはすごくシンプルですが、どう実装したものかよくわからず苦戦しました。
### 機能
- 記事の内容が変更されたら記事のみ変更
- それ以外の場合画像が追加される

## Controller 
```ruby

def update

    post = Post.find(params[:id])
    # 更新前の記事と params として渡された記事を比較している
    if post.title != params[:post][:title]

      post.update!(post_params)

    else
      post.save!

      params[:memories][:image].each do |image|
        post.memories.create(image: image, post_id: post.id)
      end
    end

    redirect_to root_path
  end
```
選択した画像を編集できた方がより良いと思いますが、こちらの機能はまた今度。。。