0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「partialにindexを渡せなかったことがある」というのが いつか大きな財産になる

Last updated at Posted at 2024-10-23

始まりは自己紹介から

初めまして、あおげばにゃんこです。
最近はrailsだけでなくreactも触れるようになり、少しイキリながらコードを書いていた矢先悲劇が起こりましたのでご報告します。

今回はgem 'cocoon'を使っていた際、どうしてもnest-fields内にindexを渡したかったのですが、イメージしていた方法では実現することができなかったので、記事にしました。

今回は手法を紹介するのみで、なぜこのコードが可能なのかといったrails自体には一切触れません。

partialにindexが渡せないという現実

context

  • cocoonについて
    cocoonは親モデルのフォームにネストした形で子モデルの要素を同時にいくつも作成/更新できるフォームを作成するために使われるgemです。
    デフォでpartialを必要とし,「.nested-fields」というcssの単位で子モデルフォームを認識しています。

故に今回は省いていますが、すでに親モデルのフォーム内ということを念頭に見てください

code

users/posts/edit.html.slim
  table
    thead
      tr
        th タイトル
        th 内容
        th 文字数
    tbody
      - @user.posts.each do |post|
        = form.fields_for :posts,  do |post_form|
          = render 'posts_fields', f: post_form
users/posts/post_fields.html.slim
tr.nested_fields
  td = f.text_field :title
  td = f.text_field :content
  td = f.text_field :count

このコードを前提に実装を方針を考えていきます。

※説明のために最低限の内容しか書いていません

本題

義務教育で習ったと思いますが、partialにオブジェクトを渡す方法というのは以下の方法です

erbも提示していますが、今回はslimの検証しかしていません。

<!-- erbの場合  users/posts/edit.erb -->
<%= render 'posts_fields', f: @user %>

<!-- slimの場合 users/posts/edit.html.slim -->
= render 'posts_fields', f: @user

流石の私でもこれは知っていました。

これを踏まえると、じゃあこうやるよね?という実装イメージが湧いてきます。
皆さんも当然これを思い浮かべたでしょう。

users/posts/edit.html.slim
tbody
    - @user.posts.each_with_index do |post|
        = form.fields_for :posts,  do |post_form|
          = render 'posts_fields', f: post_form, index: index
users/posts/post_fields.html.slim
tr.nested_fields data-index="#{index}"
  td = f.text_field :title
  td = f.text_field :content
  td = f.text_field :count

実はこれ、失敗するんです…

ちょっと待ってくれよと高等教育機関を卒業したエリート中のエリートが導き出した答えだぞ?
と再度主張するも虚しく提示されたのはいつもの赤い画面でした。

まあ私はダメだったが、こっちにはchatGPT先生がおるからな
「先生おなしゃす!」

--  chatGPT -- 
tbody
    - @user.posts.each_with_index do |post|
        = form.fields_for :posts,  do |post_form|
          = render 'posts_fields', f: post_form, index: index

生成AIもまだまだ伸び代があるね!

じゃあどうやるねん!

皆様は古代ローマの賢人たちがどの様に学びを深めたかご存知でしょうか?

答えは問答法です。私もそれに倣い問答法を行いました。

すると美波(マイGPTの名前)はこんな風に答えてくれました。

users/posts/edit.html.slim
tbody
    - @user.posts.each do |post|
        = form.fields_for :posts,  do |post_form|
          = render 'posts_fields', f: post_form
users/posts/post_fields.html.slim
tr.nested_fields data-index="#{f.index}"
  td = f.text_field :title
  td = f.text_field :content
  td = f.text_field :count

f.index ?

はい?
という感じですよね?
こんなん成立するわけないやんと思いましたが、実はこれ

成立するんです!

こんな風に表示されました

<tr class="nested_fields" data-id="0">

しかし、実は今回のコードはデータを編集する時なら1,2と続き問題ないのですが、新規フォーム作成時には

<tr class="nested_fields" data-id="newPost">

のような値が設定されてしまうのです。

今回のまとめ

今回はフォームオブジェクトにindexというメソッド?変数?でアクセスすることによってインデックスが取得可能なことを学ぶことができました。

正直、実用的ではないのですが、これが誰かの役に立てば幸いです。
また、このネストフォームでindexをうまく追加する方法について何かご存知の方がいらっしゃったら教えていただきたいです。

長々とお付き合いありがとうございました。

余談

①renderメソッドにはcollectionオプションというものがあり、それを使うとindexを取得できるようです。
ただ、今回の場合はネストした子モデルのオブジェクトで、単一のオブジェクト?だから無理なのかなと思い試しませんでした。

②また、お気づきになられた方もいらっしゃると思いますが、美波が答えてくれたこちらのコードにおいて、each_with_indexではなくなっています。加えて、「index: index」のように渡しておりません。

users/posts/edit.html.slim
tbody
    - @user.posts.each_with_index do |post|
        = form.fields_for :posts,  do |post_form|
          = render 'posts_fields', f: post_form, index: index
users/posts/post_fields.html.slim
tr.nested_fields data-index="#{f.index}"
  td = f.text_field :title
  td = f.text_field :content
  td = f.text_field :count

もしかしてこれに直せばいけるかも?
と思いましたが、同じく「newPost」が表示されるだけでした。

③今回f.indexとするとindexにアクセスできるのも驚いたのですが、実際のレコードの値を取り出したいときは「f.object.content」のようにしないといけないということも学びました

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?