【エラーメモ】newとeditのビューファイルをパーシャルでまとめる

作成のフォームと編集のフォームはそれぞれビューファイルがほとんど同じ記述になっているため、パーシャル(部分テンプレート)に切り出して、renderメソッドを使って1行で呼び出せるようにしました。

newとeditの違い

この2つの記述の違いは、ルーティングのURLです。 新規作成なのか編集して更新なのか、処理が異なるためコントローラーでどっちの処理なのか判断してそれぞれのアクションに振り分けられるため。 このとき、form_withでモデルを指定すれば、URLオプションを記述しなくてもテーブルレコードのデータの有無によって自動的に振り分けてくれると認識していたけど、URL指定を省略するとnewもeditもエラーになった。 Image from Gyazo

ルーティングのパスは?と言われています。 ここで、newアクションのルーティングのパスを指定してあげると、editページでルーティングエラーが出る。 Image from Gyazo 当然、editアクションのルーティングのパスを指定してあげると、newページで同様のエラーが出る。
え、どうしたらいいの。

ちなみに、モデル指定によって自動的に振り分けられる処理を見返してみると、newとeditではなくcreateとupdateの処理に関することだったため、ページ遷移に関してはルーティングを指定しないといけないっぽい。

仮説

URLを指定してルーティングのパスを記述する必要がある。 どちらか一方のURLだと、もう一方のルーティングがエラーになる。
つまり、

  • 両方のURLを記述しないといけない。
  • 条件分岐が必要?

ここで思ったことは、条件分岐するにしても、form_withの宣言内の記述だからif~endじゃなくて1行に収まる記述にしたい。 そこでシンプルな条件分岐について調べてみた。

条件演算子

良いの見つけました。三項演算子ともいうらしい。 これだと、1行でシンプルに条件式を書ける。
条件式がtureの場合は式1が適用され、falseの場合は式2が適用される。

条件式 ? 式1(true) : 式2(false)

ちなみにif~endを使う場合は

if 条件式 then 式1 else 式2 end


となると、あと必要なのは条件式をどう書くかというところ。
テーブルレコードのデータの有無によって振り分けたいので、レコードにデータが存在しているのを確認するメソッドを調べてみた。

new_record?メソッド

これはありそうと思って調べるとすぐ見つかった。 new_record?メソッドを使うと、DBのレコードにデータが存在しない場合「true」、データが存在する場合「false」となる。 このメソッドはレコードにデータが無いことを期待しているという点に注意しないといけないと思いました。

これで条件分岐の記述をいったん書いてみよう

<%= form_with model: post, url: post.new_record? ? book_posts_path : book_post_path(post.book.id), local: true do |f| %>

こんな記述で合ってる??ってなったけど、やりたいことはコードに落として記述することができたので、とりあえずブラウザで処理を確認してみると...
お、、、いけてる、、!! 新規作成はできた!
これで編集して更新できたら成功、、、 こっちもいけた!!!
ところどころ記述ミスとかルーティングで詰まってエラー出たところは少し省いてますが、今回はわりとスムーズにエラー解決して、仮説通りうまくいってこれは嬉しい。 コードもすっきりして良い感じになった。

パーシャルの呼び出し部分について

<%= render partial: "post_form", locals: { post: @post } %>

newファイルのもeditファイルにも同様の記述で呼び出すことができる。

切り出したパーシャルではインスタンス変数の@を消して変数として記述するため、localsオプションでpostに@postを代入してパーシャル内postを@postとして使えるようにしている。 また、localsオプションを使う時は"partial"を省略できないので忘れないように記述すること。

終わりに

これで合ってるか確信はないが、どうすればやりたい実装ができるかを調べて書いてみて、合ってるんかなこれ?みたいな気持ちでやってみると思ったよりすんなりいけたので少し自信になりました。