Ruby
Rails

ActiveRecord::RecordNotFoundのエラーメッセージを翻訳する

More than 3 years have passed since last update.

はじめに

railsでUser.find(9999)などで検索して指定したIDのデータがなかった場合、ActiveRecord::RecordNotFoundという例外が発生し、 "Couldn't find User with 'id'=9999"というエラーメッセージが出ます。

そのエラーメッセージをI18nで翻訳したいと思って調査したのですが、ソースを確認すると直接エラーメッセージを書いているのでI18nのキーワードで翻訳出来ません。

ということで力技で翻訳してみました。

ActiveRecord::RecordNotFoundをrescueする。

とりあえず今回はわかりやすくControllerのactionで直接例外をキャッチする例を使います。例外が発生した場合に統一した方法でレスポンスを返したい場合は独自のMiddlewareを作っても良いと思います。

class UserController < ApplicationController

  def show
    begin
       @user = User.find(9999)
    rescue ActiveRecord::RecordNotFound => e
       # 翻訳処理を書く。   
    end
  end
end

例外メッセージを翻訳する

例外メッセージを翻訳するためのtranslate_record_not_foundメソッドを定義します。

def translate_record_not_found(error_msg)
        match = error_msg.match(/^Couldn't find ([\S].*) with '([\S]*)'=([\S].*)$/)

        # モデル名を翻訳する
        t_model = I18n.t('activerecord.models.' + match[1].underscore)
        # 属性名を翻訳する
        t_attr  = I18n.t('activerecord.attributes.' + match[1].underscore + '.' + match[2])

        I18n.t('errors.messages.not_found',
               { klass: t_model, attribute: t_attr, value: match[3] })

end

翻訳用のja.ymlファイルを用意します。

config/locales/ja.yml
ja:
  activerecord:
    models:
      user: ユーザー
    attributes:
      user:
        id: "ID"

  errors:
    messages:
      not_found: "%{klass}の%{attribute}=`%{value}`は見つかりません"

そして、先ほど例外をキャッチしていたactionにtranslate_record_not_foundメソッドを使って翻訳した例外メッセージで再度例外を発生させます。

class UserController < ApplicationController

  def show
    begin
       @user = User.find(9999)
    rescue ActiveRecord::RecordNotFound => e
       raise ActiveRecord::RecordNotFound, translate_record_not_found(error_msg)
    end
  end
end

あとはほかの箇所で例外を補足してエラーメッセージを表示するとメッセージが翻訳されているはずです。