[Rails] DBにデータが登録されない時の対処方法

##はじめに
Rails5.0での投稿機能実装ではまったのでメモ

##環境
macOS Catalina
Ruby 2.5.1
Rails 5.0.7.2
PostgreSQL

##困り
form_forでDBにデータを登録しようと思ったが、エラー出てないのにデータ保存されていなかった

##対処した方法
1. GUIアプリで確認
2. 保存されない原因を確認①(pry-rails)
3. ハッシュの二重構造を解消
4. 保存されない原因を確認②(メソッドの後ろに"!")
5. バリデーションによるエラーを解消

###1. GUIアプリで確認
- PostgreSQLを使用しているので、Posticoをインストール
- GUIアプリでDBが見れるようになったら、もう一度投稿してみる
- GUIアプリ上ではデータが保存されていないはず

▼インストール方法とDBへの接続方法
PostgreSQL：[PostgreSQLのデータをGUIでいじる（macOS/Postico）](https://qiita.com/junara/items/8ee572151727288f6576)
MySQL：[Sequel Proを使ってデータベースを視覚化しよう](https://pikawaka.com/tips/sequel_pro)

▼DB名の調べ方
ターミナルで「psql -l」を実行
実行結果の「app-name_development」が対象のDB名

```terminal:terminal
$ psql -l #PostgreSQLのDBを一覧で表示する

#実行結果
                                 List of databases
          Name           | Owner  | Encoding | Collate | Ctype | Access privileges 
-------------------------+--------+----------+---------+-------+-------------------
 app-name_development    | user   | UTF8     | C       | C     | 
 app-name_test           | user   | UTF8     | C       | C     | 
 postgres                | user   | UTF8     | C       | C     | 
 template0               | user   | UTF8     | C       | C     | =c/user        +
                         |        |          |         |       | user=CTc/user
 template1               | user   | UTF8     | C       | C     | =c/user        +
                         |        |          |         |       | user=CTc/user
(5 rows)
```
###2. 保存されない原因を確認①(pry-rails)
- pry-railsをインストール

```Ruby:Gemfile
group :development, :test do
  gem 'pry-rails'
end
```

```terminal:terminal
$ bundle install
```

- サーバー再起動（Ctrl + C、rails s）

- データを保存するメソッドに binding.pry

```Ruby:post_controller.rb
def create
  binding.pry #データを保存するメソッドの中に
  Post.create(post_params)
end

private
def post_params
  params.permit(:content, :image)
end
```
- もう一度投稿してみる
- 投稿画面は読み込み中になるので、ターミナルでparamsを確認

```terminal:terminal
    3: def create
 => 4:   binding.pry
    5:   Post.create(post_params)
    6: end

#params と入力
[1] pry(#<PostsController>)> params
=> <ActionController::Parameters {"utf8"=>"✓", "authenticity_token"=>"zDzgsL3bOIk0QSPOFk7eSOxvqVk18RQ0PW14dC3A7JtsLB9X2pLwvJ41V/f9WeqBDRo4Uz2PKtJDvcT4WpSCRg==", "post"=><ActionController::Parameters {"content"=>"ポストの内容テストテストテスト", "image"=>"test.jpeg"} permitted: false>, "commit"=>"投稿", "controller"=>"posts", "action"=>"create"} permitted: false>

#post_params と入力
[2] pry(#<PostsController>)> post_params
Unpermitted parameters: :utf8, :authenticity_token, :post, :commit
=> <ActionController::Parameters {} permitted: true> #ハッシュの中身が空なので登録できていない
```
ハッシュである'{}'の中身が空になっているため、
params.permit(:content, :image)では、paramsから該当するキーを取得できていないのが原因

###3. ハッシュの二重構造を解消

```Ruby:post_controller.rb
def create
  Post.create(post_params) #binding.pry は削除
end

private
def post_params
  params.require(:post).permit(:content, :image)
  #requireメソッドを使って二重構造となっているハッシュを取得
end
```
- もう一度投稿する
- Posticoで保存されているか確認　⇒　保存されていれば完了！

###4. 保存されない原因を確認②(メソッドの後ろに"!")
- 保存されない場合は別の方法で原因を確認
- 保存するメソッドの後ろに!をつける

```Ruby:post_controller.rb
def create
  Post.create!(post_params) #binding.pry は削除 #createの後ろに"!"
end
```
- この状態でもう一度投稿すると画像のようなエラーが出るはず（コードは異なります）
![validation-failed-user-must-exist.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602794/20f0772a-48ed-6ab4-602e-5c24b4fe992d.png)

⇒アソシエーションが組まれている際に、該当の外部キーが入っておらず、バリデーションで弾かれている

###5. バリデーションによるエラーを解消
- optional: trueを記載

```Ruby:post.rb
class Post < ApplicationRecord
 belongs_to :user, optional: true #optional: ture を記載
end
```
- optional: trueとは、belongs_toの外部キーのnilを許可するというもの

[Railsのbelongs_toに指定できるoptional: trueとは？](https://blog.ryskit.com/entry/2018/01/27/195442)

- 僕の場合はこれで保存できました。

##参考記事
https://teratail.com/questions/121213
https://qiita.com/tanaka7014/items/50a1a953b3f440cbe481