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

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

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

:::note warn
今回は手法を紹介するのみで、なぜこのコードが可能なのかといった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
```
このコードを前提に実装を方針を考えていきます。

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

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

:::note warn
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」のようにしないといけないということも学びました