Active Storage導入方法【投稿機能＋画像の実装と合わせてご紹介】

#導入
現在制作中のアプリケーションに投稿機能を実装したいと思います。
投稿には文章と画像を投稿することが可能になってます。Twitterの投稿機能をイメージしていただくとわかりやすいと思います。

#開発環境
ruby '2.6.5'
rails '6.0.0'


#現状
![スクリーンショット 2021-02-05 22.20.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792954/3097cbff-972e-8fdf-0322-3ba291986275.png)
アプリケーションには、ユーザー管理機能（devise）が、すでに実装されています。
ログインするとトップ画面に遷移され、「こんにちは、〇〇さん」表示されます。

deviseの導入方法は下記の記事からご確認ください。
https://qiita.com/ghexcffb/items/7f2b708ed34e84cca15b

#今回のゴール（完成品写真を載せたい）

ログイン状態のユーザーが「画像＋テキスト」を投稿し、トップ画面に一覧表示できるようにします。画像についてはActiveStarageで実装します。

#実装
###postモデルとテーブルを作成します。

```:ターミナル
% rails g model post
```
マイグレーションファイルに必要なカラムを追加します。今回はpost_textです。また(references型)でuserを参照するための外部キーを記述します。

```ruby:db/migrate/xxxxxxxxxxxxx_create_posts.rb
class CreatePosts < ActiveRecord::Migration[6.0]
  def change
    create_table :posts do |t|
      t.string :post_text,        null: false
      t.references :user,         foreign_key: true 
      t.timestamps
    end
  end
end
```
マイグレーションを実行しDBにpostテーブルが存在していることを確認します。

```:ターミナル
% rails db:migrate
```
###アソシエーションの記述
PostモデルとUserモデルにアソシエーションを記述します。

```ruby:models/post.rb
class Post < ApplicationRecord
  belongs_to :user
end
```

```ruby:model/user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

         has_many :posts, dependent: :destroy

end
```

##Active Strageの導入
GemfileにGemを記述しインストールします。

```ruby:Gemfile
gem 'mini_magick'
gem 'image_processing', '~> 1.2'
```
```:ターミナル
% bundle install
```

次にActive Strageをインストールし、マイグレーションを実行します。

```:ターミナル
rails active_storage:install
```

```:ターミナル
rails db:migrate
```

postモデルにimageカラムとのアソシエーションを記述します。

```ruby:models/post.rb
class Post < ApplicationRecord
  belongs_to :user
  has_one_attached :image
end
```

##バリデーションの設定
最後に投稿機能のルールに合うようにバリデーションを設定します。今回は投稿内容のpost_text、image共に必須になります。したがって両者のバリデーションを設定します。
条件が複数存在しわかりにくい時は、以下のように表で整理することでミスをなくせると思います。

###条件
|カラム名|必須|
|:--:|:--:|:--:|
|post_text|◯|
|image|◯|

###バリデーション
```ruby:model/post.rb
class Post < ApplicationRecord
  belongs_to :user
  has_one_attached :image

  validates :post_text, presence: true
  validates :image, presence: true
end
```

##アクションとルーティングの設定
投稿機能と表示に必要なアクションとルーティングを設定します。投稿なのでnewとcreateのアクションを設定します。
同時にストロングパラメーターも記述します。post_textとimageを許可しましょう。

```ruby:controller/post_controller.rb
class PostsController < ApplicationController

  def index
    @posts = Post.all
  end

  def new
    @post = Post.new 
  end

  def create
    @post = Post.new(post_params)
    if @post.save             #もしセーブしたら
      redirect_to root_path   #root_pathに戻る
    else                      #それ以外なら
      render :new             #newのページに戻るよ
    end
  end

 private
#ストロングパラメーター↓
  def post_params
    params.require(:post).permit(:post_text, :image).merge(user_id: current_user.id)
  end
#ストロングパラメーター↑
end
```

```ruby:config/routes.rb
Rails.application.routes.draw do
  devise_for :users
  get 'posts/index'
  root to:'posts#index'
  resources :posts           #post全てのルーティングを設定
end
```

##ビューファイルの設置
最後に新規投稿画面に必要なビューを設置します。完成ビューは以下の写真です。
これで実際に投稿するとDBに反映されトップ画面に戻ってきます。
![スクリーンショット 2021-02-05 23.51.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792954/be2193c7-77b1-e318-b93e-820f00feb58b.png)

```erb:view/posts/new.html.erb
<h1 class="post_new_title">新規post</h1>

<%= form_with(model: @post, local: true) do |f| %>

  <div class="field">
    <%= f.label :post_text, "投稿内容" %><br />
    <%= f.text_field :post_text %>
  </div>

  <div class="field">
    <%= f.label :image, "画像" %><br />
    <%= f.file_field :image %>
  </div>

  <div class="actions">
    <%= f.submit "保存する", class: :form__btn  %>
  </div>

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

###一覧表示
投稿内容を一覧表示させるために、each文を使って表示します。
![スクリーンショット 2021-02-05 23.59.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792954/5eb31b22-dbb4-3803-cde1-2d0ccf76e4fa.png)


```erb:view/index.html.erb
<% @posts.each do |post| %>
 <%= link_to image_tag(post.image), post_path(post.id) %>
 <%= link_to post.post_text, post_path(post.id) %>
 <%= link_to "by#{post.user.last_name}", root_path(post.user.id) %>
<% end %>
```