8
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Posted at

はじめに

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

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

環境

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

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

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

Image from Gyazo

# 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>

  以下省略

# 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が正しく記載されているか?を確認

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

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

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

$ 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がそれぞれ結びついています)

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

# 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を設定していました。

# 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
# models/post.rb

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

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

Image from Gyazo

正しく翻訳されたフラッシュメッセージが出てくるようになりました!
(ちなみに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

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

+ validates :prefecture_id, presence: true

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

最後に

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

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

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

8
4
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
8
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?