form_with使用時に結びつきのないmodelがi18nで翻訳されなかった時の話

## はじめに
こんにちは、Webエンジニア目指して学習中のさばと申します🐟（X：@saba7678pg）
昨夜戦っていたエラーとの痕跡を折角なので記録しておこうと思います。

:::note warn
もっとこうした方が良い、この方法だと不都合が起きる等
何かございましたら、お手数ですがコメント・DM等でお知らせ頂けますと幸いです。
:::



## 環境
- Docker環境下
  - ruby 3.2.2
  - rails 7.1.2
  - rails-i18n 7.0.8

## フラッシュメッセージが"一部"正しく翻訳されない

以下画像のように、フラッシュメッセージが一部だけ翻訳されない不具合が出ておりました。

[![Image from Gyazo](https://i.gyazo.com/96b60cfc87d63a36ac0510d45cf64b26.png)](https://gyazo.com/96b60cfc87d63a36ac0510d45cf64b26)

``` ruby
# views/posts/_form.html.erb

<%= form_with model: post, local: true, class: "space-y-4" do |f| %>
  <%= render 'shared/error_messages', model: f.object %>

  <!-- 都道府県のプルダウンメニュー -->
  <div>
    <%= f.label :prefecture_id, class: "block text-sm font-medium text-gray-700" %>
    <%= f.collection_select :prefecture_id, Prefecture.all, :id, :name, {prompt: "選択必須"}, {class: "select select-bordered select-sm w-full max-w-xs"} %>
  </div>

  <!-- 観光地名のテキストフィールド -->
  <div>
    <%= f.label :location, class: "block text-sm font-medium text-gray-700" %>
    <%= f.text_field :location, placeholder: "観光地名やスポット名を記入してください", class: "input input-bordered input-sm w-full max-w-xs" %>
  </div>

  以下省略

```

``` ruby
# views/shared/_error_messages.html.erb
<% if model.errors.any? %>
  <div class="bg-yellow-100 border-l-4 border-yellow-500 text-yellow-700 p-4" role="alert">
    <ul>
      <% model.errors.full_messages.each do |message| %>
        <li class="list-disc list-inside"><%= message %></li>
      <% end %>
    </ul>
  </div>
<% end %>
```

以下、私の対応工程・上手くいかなかった点がつらつら書いてありますので、
結論を知りたい方は目次の**解決の兆し・対応方法**へ飛んでくださいませ🙇‍♂️🙇‍♂️

## 対応①：`ja.yml`の確認

そもそもja.ymlが正しく記載されているか？を確認

``` zsh
irb(main):001> I18n.t('activerecord.attributes.post.prefecture_id')
=> "都道府県"
irb(main):004> I18n.t('activerecord.models.prefecture')
=> "都道府県"
```

問題なく設定できているように思えます。

## 対応②：そもそもフラッシュメッセージの中身がどうなってるかを確認してみる

``` zsh
$ rails c
irb(main):001> post = Post.new
=> 
#<Post:0x0000ffffb2b583c8
...
irb(main):002> post.valid?
=> false
irb(main):003> post.errors.full_messages
=> ["Userを入力してください", "Prefectureを入力してください", "観光地・スポットを入力してください", "旅行の思い出を入力してください"]
```

ログインしているユーザーのみが投稿機能を使えるので、そもそもUserが空になるという状態は起きえないのですが、
ここでPrefecture同様Userも翻訳できていないことが分かりました。
どうやら`form_with`で関連づけているモデルがPostなので、
Postと関係を持っている他テーブルの情報取得の際に翻訳エラーが起きているようです。
（今回はPostモデルにUserとPrefectureがそれぞれ結びついています）

## 対応③：モデルを明示して記載してみる

``` diff
# posts/_form.html.erb

- <%= f.label :prefecture_id, class: "block text-sm font-medium text-gray-700" %>
+ <%= f.label :prefecture_id, Post.human_attribute_name("prefecture_id"), class: "block text-sm font-medium text-gray-700" %>

or

Prefecture.human_attribute_name("name")

```

ラベルは置き換わるけれど、出ているフラッシュメッセージのPrefectureは変化がないので呼び出し方自体に問題があるのか…?

## 解決の兆し①：postモデルにprefecture_idのバリデーションをかけていない

そもそもpostsのprefecture_idにはバリデーションをかけておらず、
prefecturesテーブルでnull: falseを設定していました。

``` ruby
# schema.rb
  create_table "posts", force: :cascade do |t|
    t.bigint "user_id"
    t.bigint "prefecture_id"
    t.string "text", null: false
    t.index ["prefecture_id"], name: "index_posts_on_prefecture_id"
    t.index ["user_id"], name: "index_posts_on_user_id"
  end

  create_table "prefectures", force: :cascade do |t|
    t.string "name", null: false
    t.index ["name"], name: "index_prefectures_on_name", unique: true
  end
```

``` ruby
# models/post.rb

class Post < ApplicationRecord
  belongs_to :user
  belongs_to :prefecture
以下省略
```

試しに`validates :prefecture_id, presence: true`を追記してみると

[![Image from Gyazo](https://i.gyazo.com/2a8b260238b003e2f20256420c94f40e.png)](https://gyazo.com/2a8b260238b003e2f20256420c94f40e)

正しく翻訳されたフラッシュメッセージが出てくるようになりました！
（ちなみにPrefecture・都道府県を入力してくださいと2つのエラーが出ていますが、
正しく都道府県を入力した状態にするとどちらのエラーも消えました）

となると、Prefectureはどこから来てるんだ…？

## 解決の兆し②：`belongs_to`によるバリデーションを緩和する

Rails5以降、`belongs_to`関連付けの際に`required: true`がデフォルト設定されているようです。
関連する`prefecture`が存在しない場合、Postオブジェクトのバリデーションに失敗する、
フラッシュメッセージに出てきていた`Prefecture`はここから来ていたのでしょうか。

この挙動を`belongs_to :prefecture, optional: true`とし、バリデーションを無効にすることで
「Prefectureを入力してください」というフラッシュメッセージは出なくなりました👏

## 対応方法:`models/post.rb`のバリデーション変更

[![Image from Gyazo](https://i.gyazo.com/06324e97ad3e0de9a09265e2499dc8b7.png)](https://gyazo.com/06324e97ad3e0de9a09265e2499dc8b7)

``` diff
class Post < ApplicationRecord
  belongs_to :user
- belongs_to :prefecture
+ belongs_to :prefecture, optional: true

+ validates :prefecture_id, presence: true

```

``` zhs
 #<Post:0x0000ffff9a849258
  id: 3,
  user_id: 1,
  location: "test",
  prefecture_id: 1,
以下省略
```

## 最後に

GPT「i18nのインデントを確認してみて！」
🐟「インデントも問題ないよ！」
GPT「OK、それじゃあ今度はインデントを確認してみて！」
🎣「合っとるだろうがよおᗦ↞◅」

不毛なやり取りを続けておりました。

引き続き個人開発で遭遇したエラーで学びがあれば記事に書いていこうと思います。
ここまで読んでいただきありがとうございました🐟