Ruby on Rails　初心者向け！！新規投稿機能まとめ

# はじめに
　Railsを使って何かサービスを作りたいと思い学習をはじめ、備忘録として記事に残して行こうと思いました。
　今回はWebアプリの新規投稿機能を学習しました。間違った認識やアドバイスなどがあればコメントお願いします。

# 開発環境
- Docker
- ruby 2.3.7
- Rails 5.2.4.4
- MySQL 5.7.32

# 事前準備
　あらかじめPostモデルの作成、マイグレージョンファイルの編集を行いました。マイグレーションファイルは以下のように編集しました。

```ruby:マイグレーションファイル
class CreatePosts < ActiveRecord::Migration[5.2]
  def change
    create_table :posts do |t|
      # ここから
      t.string :title
      t.string :body
      # ここまで編集
      t.timestamps
    end
  end
end
```

テーブルの作成を反映させるためにターミナルからコマンドを打ち込みます。

```
$ rails db:migrate

== 20210104014856 CreatePosts: migrating ======================================
-- create_table(:posts)
   -> 0.0193s
== 20210104014856 CreatePosts: migrated (0.0202s) =============================
```

これでテーブルが作成できたので、準備は完了です。

# コントローラーに定義するアクション一覧

Railsでは、Webアプリケーションの基本的な機能を下記のアクション名で定義するのが一般的です。

| アクション名 |　役割　|
|:----------:|:----- |
|new|データの新規作成フォームを作成する|
|create|データの追加・保存を行う|
|index|データの一覧表示を行う|
|show|データの詳細表示を行う|
|edit|データの編集フォームを作成する|
|update|データの更新を行う|
|delete|データの削除を行う|

# 新規作成機能（new、create）

## コントローラーの作成

ターミナルでcontroller（コントローラー）を作成します。

```
rails g controller posts
```

```
rails g controller コントローラー名　アクション名
```
上記のようにアクション名を付け加えると、自動でアクションとそのアクションに対応するルーティング、view(ビュー)も自動で作成してくれるみたいですが、今回は流れをつかむためにアクション名はつけずに進めていきます。

では、作成したコントローラーにnewアクションを定義します。

```ruby:posts_controller.rb
class PostsController < ApplicationController
  # ここから
  def new
  end
  # ここまで追加
end
```

## ルーティングの設定
次はルーティングの設定をapp/config/routes.rbでしていきます。

```ruby:route.rb
Rails.application.routes.draw do
  # ここから
  get 'posts/new' => 'posts#new'
  # ここまで追加
end
```

　この記述では、「HTTPメソッドのGETでposts/newのパスにアクセスすると、postsコントローラーのnewアクションが呼び出される。」という意味になります。

## ビューの作成
　次にpostコントローラーのnewアクションが呼ばれた時に、ユーザーに表示するview(ビュー)ファイルを作成します。コントローラー作成時にapp/viewsにpostsフォルダが作成されているので、その直下にnew.html.rbファイルを作成します。

作成したファイルを開いて、わかりやすいようにページ名を記述しておきます。

```html:new.html.rb
<h1>投稿フォーム</h1>
```

これでブラウザから/posts/newのパスにアクセスすると、先ほど作成したviewファイルが表示されるようになりました。

![スクリーンショット 2021-01-04 20.31.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/651278/8b219f01-7a9f-3e87-6ab1-b1110e26f9a4.png)


## 投稿フォームの作成
　投稿を新規作成するには、空のモデルをフォームに渡す必要があります。postsコントローラーのnewアクションで

```ruby:posts_controller.rb
class PostsController < ApplicationController
  def new
      #ここから
      @post = Post.new
      #ここまで追加
  end
end
```
のように記述すると、空のモデルが作られインスタンス変数である@postに代入されviewで使用できるようになります。

　次に新規投稿するために必要な投稿フォームを作成していきます。Railsには、viewから呼び出す共通処理をまとめた「ヘルパーメソッド」が用意されており、今回はこの1つのform_forヘルパーを使用していきます。

```ERB:new.html.rb
<h1>投稿フォーム</h1>
# ここから
<%= form_for(@post, url: '/posts') do |f| %>
  <h3>タイトル</h3>
  <%= f.text_field :title %>
  <h3>本文</h3>
  <%= f.text_area :body %>
  <%= f.submit '投稿' %>
<% end %>
# ここまで追加
```

　form_forヘルパーの第一引数に空のモデルを代入してインスタンス変数を指定することで、フォームとPostモデルが関連づけられます。第２引数には、送信先のパスを指定します。今回はcreateアクションでデータベースへの保存処理を書くのでそこまでのパスを指定しました。

ここまででフォームの入力まで実装でき、投稿フォームが追加されています。
![スクリーンショット 2021-01-04 20.24.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/651278/c3f8433d-90b1-e697-1dd1-5da225e8301c.png)


## データの保存機能の実装（create）
  まずルーティングを設定していきます。

```rb:route.rb
Rails.application.routes.draw do
  get 'posts/new' => 'posts#new'
  # ここから
  post 'posts' => 'posts#create'
  # ここまで追加
end
```

コントローラにフォームデータを送信する場合、POSTメソッドを使用します。これでフォームを送信した際に、postsコントローラーのcreateアクションを呼び出すように設定できました。

　次にデータの保存処理を行うcreateアクションを実装していきます。newアクションの下にこのように記述します。

```ruby:posts_controller.rb
  def create
    post = Post.new(post_params)
    post.save
    redirect_to '/posts/new'
  end

  private
  def post_params
    params.require(:post).permit(:title, :body)
  end
```

　フォームからデーターを送信する際に、「マスアサインメント脆弱性」というデータ送信時の不正なリクエストによって、予期しない値を変更されてしまう、セキュリティ上の問題があります。Railsではこれを防ぐために「ストロングパラメータ」という仕組みが用意されています。privateから下のコードがそれです。

　ストロングパラメータは、フォームから送信されたデータを受け取り、createやupdateに渡す役割があります。また先ほどの不正なアクセスを防ぐ役割もあります。requireでデータのオブジェクト名を指定し、permitで値のキー名を指定しています。

createアクションの中身を一つずつみていきます。

```rb:
post = Post.new(post_params)
```

では、postモデルのインスタンスを生成し、引数でストロングパラメータからフォームから送信された値を受け取り、ローカル変数のpostに代入しています。

```rb:
post.save
```

次にsaveメソッドを使用し、DBにデータを保存します。

```rb:
redirect_to '/posts/new'
```

　最後にDBへの保存処理終了後に戻るページを指定します。今回は保存処理が終わると投稿フォームページに戻るように指定しています。

これで新規投稿機能の実装は完了しました。

![スクリーンショット 2021-01-04 20.26.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/651278/d8f01389-bf3e-1ecf-9f67-b71e322ec40a.png)

実際に投稿し、MySQLで確認してみます。

```
mysql> select * from posts;
+----+-------+-------------------+---------------------+---------------------+
| id | title | body              | created_at          | updated_at          |
+----+-------+-------------------+---------------------+---------------------+
|  1 | Hello | Hello,Hello,Hello | 2021-01-04 06:32:39 | 2021-01-04 06:32:39 |
+----+-------+-------------------+---------------------+---------------------+
1 row in set (0.00 sec)
```
先ほど投稿したデータがDBに保存されているのが確認できました。

# まとめ
- 一般的に新規投稿フォームページではnewアクション、データ保存処理はcreateアクションを使用する。
- ルーティングで、Web閲覧時はGET、サーバーへのデータ送信時はPOSTメソッドを指定する。
- Railsでは、viewから呼び出す共通処理をまとめた「ヘルパーメソッド」が用意されており、投稿フォームではform_forヘルパーが使用される、
- データ送信時のセキュリティの脆弱性を防ぐために「ストロングパラメータ」という仕組みが使われている。