【Rails】ストロングパラメータとは？ エラーとデバック方法【解説】

#ストロングパラメータとは
「Web上から入力されてきた値を制限することで、不正なパラメータを防ぐ仕組み」です。
MassAssingment脆弱性というセキュリティ上の問題に対処するための仕組みとしてRails4系から導入されたそうです。

##なぜ使うのか
投稿フォームに入力された情報はparamsによって取得できます。
その際、不正に投稿された内容がparamsに含まれているとその情報まで保存されてしまいます。

そこでストロングパラメータを設定しておくことで指定したカラムの情報(不要なカラム情報を取り除く)だけを受け取ることができます。

#ストロングパラメータについての解説
###ストロングパラメータ定義の仕方

これは現在、私が作成しているタスク管理アプリのタスクカード作成時のcreateアクションで扱おうとしてる例です。

```ruby:app/controllers/card_controller.rb
private
    def card_params
      params.require(:モデル名).permit(:カラム名1, :カラム名2,,,).merge(カラム名: 追加したいデータ値)
    end
```

実際のコードは以下になります。
cardモデルに対して、`card_title`, `memo`, 外部キーの`list_id`カラムを保存しようとしています。

```ruby:app/controllers/card_controller.rb
private
    def card_params
      params.require(:card).permit(:card_title, :memo).merge(list_id: params[:list_id])
    end
```

それぞれの中身について説明していきます。

###requireメソッド
今回の場合、createアクションで保存したいテーブルを管轄するmodelを指定します。
すなわち、`require(:card)`となります。

###permitメソッド
ユーザーがフォームなど入力してきた値について「どの値を許可して受け入れるか」を指定します。
`permit(:card_title, :memo)`を指定して受け入れています。

###mergeメソッド
ユーザーがフォームなど入力してきた値以外もテーブルに保存したい時に指定します。
今回の場合は、`list_id`という外部キーも保存したいので、`merge(list_id: params[:list_id])`となります。

#エラーと解決の鍵 『デバック』
###思い通り動作しないしエラーも発生

アプリを作り初めてタスクカード作成機能を実装している時に、
下の画像のようなエラーメッセージと共にカード作成ができない現象に悩まされました。

![Qiita【ストロングパラメータ_1】.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1210417/bf1ac987-9d02-f1f6-e441-411ed52a12a9.png)

(Listを入力してください)
「、、、。」
「入力するフォームなんてないぞ^^;」
「ん、もしかすると外部キーlist_idが何か関係しているのか！？」

「ビューはエラー画面になってないから、ローカルサーバーでエラーが出ていないかみにいこう、、」

![Qiita【ストロングパラメータ_2】.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1210417/1a10622c-00b3-a4c5-ad8b-3e7a1cbb3ffa.png)

「外部キーlist_idは取れてるみたいだし、問題なさそうだ。」　←ここで気づけたはず
ここからが時間が掛かりました。
「サーバーの一時的な不具合かな。とりあえず、リロードしてみよう！」
  (ページをリロード)

![Qiita【ストロングパラメータ_3】.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1210417/9eac8d03-2be5-6c0c-2244-4e11c8f271cc.png)

「今度は、Routing Error！？」
「一応、ルーティング確認しておくか。」
(config/routes.rbの記述には問題なし)
「だよね〜」

No route matches [GET] でググってみると、HTTPメソッドの指定が違うときにエラーになってる人が多数いた。
とりあえず、`rails routes`コマンドでルーティング確認。

![Qiita【ストロングパラメータ_4】.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1210417/a580c921-3cde-8175-45b4-29aeed62f00e.png)

「cardコントローラーのcreateアクションの、HTTPメソッドはPOSTで合ってる、、。」
「チーーーンorz」
ここで一旦、思考を変えて、YouTubeでエラー解決のために役立ちそうな、以下の動画を観てみました。


https://www.youtube.com/watch?v=5fyrGslhUcY

この動画は、とても参考になりました。エラーで悩んでいる初学者の方は絶対に観たほうが良いです！


ここでは、

- Railsのエラー画面の見方
- `better_errors`&`binding_of_caller`というデバック用gemの導入方法と使用方法
- Railsには標準で、byebugというデバックツールがあることを知りました。
(他にもたくさん参考になることがありました)

###救世主 『デバッカー』

エラー画面は出ていないので、byebugで何か原因が掴めるのではないかと早速使って見ることにしました。

<details><summary>byebugとは</summary>
Rail標準で装備されてデバックツールです。
一行ごとにプログラムを実行してその時に宣言されている変数の中身をみながら動作を確認する事が出来ます。
</details>


実際にbyebugを使って、card_paramsでキーが取れているか中身を確認していきます。
カード作成時の動作を確認するため、下の画像の位置に`byebug`を記述します。
`byebug`の代わりに`debugger`と記述しても同じ動作をします。

![Qiita【ストロングパラメータ_5】.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1210417/94d9296a-a642-5acb-4811-270ef99bffe7.png)

byebugが起動したら、`card_params`と入力してパラメーターを確認します。
下の画像でもわかるように、`card_title`、 `memo`、　外部キーの`list_id`を取得したいのに
外部キーの`list_id`が取得できていませんでした。

![Qiita【ストロングパラメータ_6】.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1210417/6e3c0bcf-7c53-668a-9f93-262a07c24e4b.png)


ここで初めて、外部キー`list_id` が取得できていないことが明確になりました。
最初の見当の付け方は合っていたけど、ここまで時間がかかった、、。


さて、ここからが本題、外部キー`list_id`を取得するにはどういう記述をしたらいいのか。

##外部キーの取得の仕方
結論から言うと、`merge`メソッドを用いた記述をすることです。

card_paramsメソッドから、`card_title`, `memo`, 外部キー`list_id` を取得したいが、
下の画像の記述だと、`card_title`, `memo` しか取得されておらず、外部キー`list_id`が取得できていませんでした。

```ruby:app/controllers/card_controller.rb
private
    def card_params
      params.require(:card).permit(:card_title, :memo, :list_id) #←記述方法が間違っている
    end
```


正しいコードは以下になります。
cardモデルに対して、`card_title`, `memo`, 外部キーの`list_id`カラムを保存しようとしています。

```ruby:app/controllers/card_controller.rb
private
    def card_params
      params.require(:card).permit(:card_title, :memo).merge(list_id: params[:list_id])
    end
```

byebugでデバックすると、外部キー`list_id`を取得できていました。(下の画像)

![Qiita【ストロングパラメータ_7】.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1210417/61a115bc-c591-cfc5-27dd-ccae0a94ce0e.png)

これで無事にタスク管理アプリのタスクカード作成ができるようになりました。

今回、学んだこととしては
デバックツールを使いこなせることでエラーは発生時の対応効率が格段に上がることを再認識しました。
デバック方法は、byebug以外にもたくさんあることを知るきっかけにもなったので、
少しづつデバック方法の幅を広げていけるよう日々研鑽していきます！

以上になります。
最後まで、読んで頂きありがとうございました。
プログラミング初学者なので、間違い等ありましたらご指摘いただけたら幸いです。
また、不明点や質問等があれば気軽にしてください！

##参考

https://www.youtube.com/watch?v=5fyrGslhUcY

https://menta.work/post/detail/2656/G3ipLrKsULvKraFJLK1m