translation missing: ja. ~~ ?? 見たいエラーはそれじゃねえ！！

# はじめに
こんにちは！
<font color="red">**DMM WEBCAMP mentor Advent Calendar 2022**</font> :christmas_tree: **7日目** を担当します @Keichan_15 です！

今年のAdvent Calendarでは、ありがたいことに [1日目](https://qiita.com/Keichan_15/items/eae011dccea44abda768) を担当させて頂きました。初執筆ながら多くの皆様にお読み頂けて感無量です、。ありがとうございます！
~~ちなみに実を言いますと、まだもう1記事執筆予定なのです…。早くポケモンやりたい…ニャオハ…:zipper_mouth:~~


少々前置きが長くなりましたが、主に本記事では、 **Rails で I18n 導入後に 「translation missing: ja.」系のエラー** が出た時の対処法について紹介していきたいと思います！
ちなみに、今回の記事は1日目で紹介した **I18n** に非常に関連する内容となっておりますので、まだ読んでないよ！って方は是非とも事前にお読み頂けますと、より理解が深まるかと思います！:raised_hands:

今回はどのようなパターンを想定した内容かと言いますと、
- **Let's Rails開発！！**
- **ある程度実装進んできたからちょっとここで 日本語化 導入しよーっと！**
- **おい！ <font color="red">本来見たいエラーよりも先に対訳用意しろって言われてる！でも対訳いちいち全部入れるの面倒だよ！</font> とりあえず今出てるエラーを見せてくれ…！**

とお困りの方への記事となっております！

特に実装途中で日本語化を行った方、見たいエラーよりも先行して出てくるこのエラーに悩まされることが多いのではないでしょうか。
自身も「全部翻訳入れるの面倒や…。コピー&ペーストするのも面倒や…。」という ~~究極の面倒くさがり~~ 人間なので、今回は **2STEP** に分けてこの問題を解決していきます！

よろしくお願い致します！


# ※ 2STEPへ歩み出す前に(裏ルートがあります)

実はこのエラーですが、有効な解決策が既に存在しており、エラー文をコピってそれとなく記事を漁ってみると、
- エラーで表示されている、用意されていない対訳をja.ymlに記載しよう！
- [ここ](https://github.com/tigrish/devise-i18n/blob/master/rails/locales/ja.yml) とか [ここ](https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/ja.yml) の対訳日本語ver.を一旦全部持ってきて、とりあえず貼っておこう！

その他、関連記事が発見できると思います。以下に参考記事をご紹介します。

**参考**

https://qiita.com/ken_sasaki2/items/0c566ced53f7ee47d67d

https://qiita.com/moperon/items/da8cd6e674dba2552c42

https://qiita.com/tetokun/items/cb5a819aef5bb00fe038


出ているエラーの対訳をその都度 `ja.yml` に転記したり、コピペの時間が十分にあったり、という方には本記事はあまり参考にならないかもしれません…。
何せ、「とりあえず目の前のエラーだけ見せてくれ！早よ！」って方に向けた内容です。時間は有限ですから…1秒も無駄に出来ないんです僕の人生。。

# 前提環境
- Ruby 3.1.2
- Rails 6.1.7
- yarn 1.22.19

本記事では、簡単なRailsアプリケーションを用いながら説明していきます。

前提として、
- ユーザー情報を保持する **Users** テーブル
- 投稿した記事の内容を保持する **Lists** テーブル

を作成しています。ER図は以下の通りです。

![2022-12-04 (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2798073/fc65f282-d807-a712-3282-38c83660fe83.png)

:::note warn
**注意① Users テーブルについて**
今回 User モデルの作成には **devise** を使用して実装しています。deviseについてザックリ説明すると、「Railsで作成したWebアプリケーションに簡単に認証機能(サインイン・サインアウト)を実装できるgem」になります。
具体的な使用方法については執筆の尺の関係上、割愛させて頂きます！(ゴメンネ :disappointed_relieved:)
::: 

:::note warn
**注意② I18n について**
ここでの I18n は **configファイルへの追記やja.ymlを作成している状態を前提** とします。
導入方法については執筆の尺の関係上、今回は触れませんのでご了承ください！(ゴメンネ :disappointed_relieved:)
:::

:::note warn
**注意③ enum について**
これも **導入されていることを前提** とします。
導入方法については…(以下略)(ゴメンネ :disappointed_relieved:)
:::

# 現状

状況としては、記事の投稿をしたのに投稿内容が反映されない場面を想定して頂きたいです。
![2022-12-05 (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2798073/8d1cad92-a447-006f-5723-d704e006fe48.png)
記事作成フォーム に 記事のタイトル・内容 を記入して `投稿` ボタンを押しても…
![2022-12-05 (10).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2798073/646606d2-2700-6084-aa06-f95a07ed1b95.png)
**なぜでしょう。投稿内容が一覧に表示されていません！**
 
原因を調査するため ~~我々はアマゾンの奥地へと… etc.~~ `save!` メソッドを用いて確認します。こちらも詳細は割愛しますが、ザックリ説明すると **保存が出来なかった場合にのみ例外を発生させます。** なんて便利な子なの…。

https://api.rubyonrails.org/classes/ActiveRecord/RecordInvalid.html#method-c-new


```ruby:app/controllers/lists_controller.rb
class ListsController < ApplicationController

  def new
    @list = List.new
  end

  def index
    @lists = List.all
  end

  def create
    @list = List.new(list_params)
    @list.save! ← ココ！！
    redirect_to lists_path
  end

  private

  def list_params
    params.require(:list).permit(:title, :body)
  end

end
```
よし！これで原因を確認できるぞ！と思ったら…
![2022-12-07 (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2798073/77a0a712-e325-4aca-6649-8710ad4f61a2.png)
`translation missing: ja.activerecord.errors.messages.record_invalid` ?? 見たいエラーはそれじゃないんだよなあ…。

ここで I18n 大好きマンの方は薄々お気付きかと思いますが、このエラーの意味を翻訳サイトに突っ込むと「翻訳無いで！ja.activerecord.errors.messages.record_invalidの翻訳が！早よ用意セエ！」って出てくると思います。優秀な翻訳サイトです、それ。

いやでもね、configには設定してるし、ここだけ翻訳一旦あればええんですよってのが今回のパターン。
```ruby:config/application.rb

module ご自身のアプリケーション名
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 6.1

    # Configuration for the application, engines, and railties goes here.
    #
    # These settings can be overridden in specific environments using the files
    # in config/environments, which are processed later.
    #
    # config.time_zone = "Central Time (US & Canada)"
    # config.eager_load_paths << Rails.root.join("extras")
    config.i18n.default_locale = :ja
  end

```
```yml:config/locales/ja.yml
ja:
  enums:
    order:
      payment_method:
         credit_card: "クレジットカード"
         transfer: "銀行振込"
```
そうなんです。今回別に `enum` を使用している所だけ日本語化出来たら良いんです。 
日本語化の方色々直せヨ！と、先行して主張するオラオラ系エラー上司に負けちゃってるんです。本当に見たい、バリバリエリート系エラー部下くんの悲しき現実。これが縦社会です。

エリートが花開く未来を共に見届けるため、簡単 **2STEP** の旅に出て上司からの圧力を跳ね飛ばそう！という内容でございます！:airplane:

# STEP① コメントアウト、便利やなあ～
まず、STEP① で行う内容は **config/application.rb から日本語化の設定コードをコメントアウトする** になります！

```ruby:config/application.rb

module ご自身のアプリケーション名
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 6.1

    # Configuration for the application, engines, and railties goes here.
    #
    # These settings can be overridden in specific environments using the files
    # in config/environments, which are processed later.
    #
    # config.time_zone = "Central Time (US & Canada)"
    # config.eager_load_paths << Rails.root.join("extras")
    config.i18n.default_locale = :ja
  end

```

Railsにて I18n を使用し日本語化を行っている場合、
```ruby:config/application.rb
    config.i18n.default_locale = :ja
```
この1行を追加していると思います。多分してます。この1行を、
```ruby:config/application.rb
   # config.i18n.default_locale = :ja
```
このように **コメントアウト** してあげましょう！

この1行は翻訳のデフォルト言語を日本語に設定するための記述ですが、このように変更することで　**一時的に日本語化の設定を無効** にしています。

なんて簡単な STEP1 なのでしょうか！！:raised_hands:

# STEP② コメントアウト、正義やなあ～
STEP② もこれまたコメントアウトになります。 **ja.ymlの中身をコメントアウト** しましょう！

```yml:config/locales/ja.yml
ja:
  enums:
    order:
      payment_method:
         credit_card: "クレジットカード"
         transfer: "銀行振込"
```
こちらの `config/locales/ja.yml` の `ja:` 以下の記述を、
```yml:config/locales/ja.yml
ja:
  # enums:
  #   order:
  #     payment_method:
  #       credit_card: "クレジットカード"
  #       transfer: "銀行振込"
``` 
このように **コメントアウト** してあげましょう！

ここでのポイントですが `config/locales/ja.yml` の **中身全てをコメントアウトしてしまうとエラーが出てしまう** という点です。
![2022-12-05 (14).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2798073/31f8b0fc-d9b2-d7e3-1551-839dad7eb7e1.png)
こんな感じに…。
ymlファイルの中身が全て空っぽの状態でもエラーが出てしまいます。一行だけ残すのがミソってやつです。

以上、2STEPが完了しましたら **必ず** `rails s` し直してください！画面リロードだけでは変更が反映されない場合が考えられます。ここは面倒くさがり屋さんでもやりましょうね…。:frowning2:

# いよいよ待望のエラーとご対面…！？
果たして今回の2STEPを乗り越えると、待望のエラーが出てくれるのか！？
期待と共に再度 `投稿` ボタンを押下すると…
![2022-12-05 (16).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2798073/82341e75-466c-de65-08fd-2eb310e5059b.png)
**やったー！見たいエラーが出てきてくれたよ～！:sob:**
ってエラーの先に出てくるのがまたエラーかよ…という話ではあるんですけどね（笑）

ちなみにこのエラーですが、Listsテーブルの外部キー(FK)に設定しているuser_idに対して、ログイン中のユーザーのid(current_user.id)を入れてあげることで解決します。
今回の記事内容から若干反れるため、ご興味ある方は以下の「解決方法」を覗いてみてくださいね! :thumbsup:

<details><summary>解決方法</summary>

## ★完成コード
```ruby:app/controllers/lists_controller.rb
class ListsController < ApplicationController

  def new
    @list = List.new
  end

  def index
    @lists = List.all
  end

  def create
    @list = List.new(list_params)
    @list.user_id = current_user.id
    @list.save
    redirect_to lists_path
  end

  private

  def list_params
    params.require(:list).permit(:title, :body)
  end

end
```

## 解説

### 〇現状起きている問題
まずは、現在発生しているエラーについて確認していきましょう！
画面が真っ赤真っ赤で逃げたしたくなりますが、エラーには問題解決への糸口がギュッと詰まっていますので見て損はありません！仲良くなればこっちのもんです。
![2022-12-05 (16).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2798073/f94d3602-8146-bfef-dcce-60afe115b267.png)

着目すべき箇所は上から2行目の `Validation failed: User must exist` の表示です。
ここから読み取れるのは **Userモデルにデータが入っておらず、保存時にバリデーションで弾かれてしまっている** という点です。

イメージとしては、記事のタイトル・本文は問題無くデータが渡っているのですが、 **「誰が」その記事を投稿したのか** という情報が不足してしまっています。

ここで冒頭に紹介したER図を確認してみましょう。
![2022-12-04 (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2798073/fc65f282-d807-a712-3282-38c83660fe83.png)
記事のデータを保持するテーブルは Lists テーブルでしたね。では Lists テーブルの中で 誰がその記事を投稿したのか の **「誰が」** に該当するデータが入るのはどのカラムになるでしょうか？

そうです、 `user_id` ですね！
この `user_id` には記事を投稿したユーザーのidが入ります。このカラムがあることによって、「誰が」の情報が補完され、記事のデータが作成されるようになります！
今や日常生活と切って離せないSNSですが、誰がそのツイートをしたのか、誰がその写真をアップしたのか など、いわゆる `Who?` の情報は極めて重要ですよね！

では実際にコードに修正を加えていきましょう！

### ★問題の修正
まずは修正前のコードを確認します。
```ruby:app/controllers/lists_controller.rb
class ListsController < ApplicationController

  def new
    @list = List.new
  end

  def index
    @lists = List.all
  end

  def create
    @list = List.new(list_params)
    @list.save!
    redirect_to lists_path
  end

  private

  def list_params
    params.require(:list).permit(:title, :body)
  end

end
```

まず最初に、 `create` アクション内で変更した `save!` メソッドを通常の `save` メソッドに戻します。
```ruby:app/controllers/lists_controller.rb
  def create
    @list = List.new(list_params)
    @list.save ← save! から save に変更！
    redirect_to lists_path
  end
```
次に、「誰が」の情報を追加するために `@list = List.new(list_params)` の1行下から記述を追加していきます。

今回追加する対象となるカラムは `user_id` でした。このカラムに、記事を投稿したユーザーのidを代入します。ここでの「記事を投稿したユーザー」は、今何をしているユーザーと同じ と捉えることができるでしょうか？


今回は前提としてdeviseを使用し、ユーザーはログイン済である状況を想定します。この条件を踏まえて別の捉え方をすると **今ログインしているユーザー** と一緒である、とも取れますよね。この別視点での考え方が非常に重要です。

また、deviseでは「ログインしているユーザーの情報」を取得する手段として、 **current_〇〇** と呼ばれるヘルパーメソッド(〇〇はdeviseを使用して作成したモデル名が入る)が使用できましたね。個人的にこのヘルパーメソッドについて分かりやすいなという記事がありましたので、「解決方法」のすぐ下に記載しております。是非こちらも確認してみてください！

代入すべきカラム、使用すべきヘルパーメソッドが確認できたところでコードを修正していきます。
```ruby:app/controllers/lists_controller.rb
  def create
    @list = List.new(list_params)
    @list.user_id = current_user.id ← この1行を追加！
    @list.save
    redirect_to lists_path
  end
```
```ruby:app/controllers/lists_controller.rb
    @list.user_id = current_user.id
```
Lists テーブル内の `user_id` カラムであることを示すため、代入すべきカラムの記述は `@list.user_id` になります。
そして、そのカラムに `current_user.id` と記述することで、今ログインしているユーザーのidを代入することができます。

このように記述することで `Lists` テーブルの `user_id` カラムに適切なデータが渡り、記事の投稿が出来ました！めでたし、めでたし。
![2022-12-05 (19).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2798073/93d4c822-5b57-5e26-d891-d96150fddf3d.png)

### ◎まとめ
- まずはエラーをしっかり見よう！
- 別の視点から物事を捉えてみよう！
- コードいっぱい書こう！楽しい～～！

#### :speaking_head: 余談
`Validation failed: (Model name) must exist` で検索すると、大体 `optional: true` を付記して外部キーの `nil` を許可しようといった記事がヒットします。例えば以下の記事などです。

- https://qiita.com/tanaka7014/items/50a1a953b3f440cbe481

- https://pote-chil.com/rails_validation-failed-must-exist/

この方法、正直DB設計上においてFKが `nil` になるパターンってほとんど無いような気がしますし、根本的な解決になってないよねって個人的に思います。これ検索時に上の方でヒットするのでこれが正解なんだなって思っちゃうんですよね…。
特に学び始めの方は、モデルファイルにお互いアソシエーションを繋ぐ記述 `(belongs_to, has_many)` がなぜ必要なの…？って所や、外部キーってそもそもどんなデータが入るの…？みたいな所をしっかり抑えておくべきなのかな～と思いました。

</details>

#### ★解決方法の説明内で紹介した記事

https://qiita.com/tobita0000/items/866de191635e6d74e392


# おわりに
いかがでしたでしょうか。
今回は実装途中段階で日本語化を行うと、時々遭遇する可能性のある `:ja is not a valid locale` のエラーについて見てきました。
冒頭でも若干紹介したように、今回の方法以外にもこのエラーの解決方法は存在します。ご自身の実装の進捗度合いと相談しつつ、適切な方法を取り入れて頂いて素敵なWebアプリケーション開発を！:wave:
また、この記事をお読み頂き少しでも同じエラーでお悩みの方の助けとなれば幸いです。
最後までお読み頂き、ありがとうございました～～！