LoginSignup
19
12

More than 5 years have passed since last update.

Rails モデル名の i18n のもう一つの方法

Posted at

やりたいこと

Ruby on Rails で,モデル名の日本語を表示したいとする。

例えば会員情報を担う Member というモデルがあって,これを「会員」と表示させたい。
「会員一覧」「会員の新規追加」「会員を削除しました。」といったように。

ふつうのやり方

Rails に備わっている i18n(internationalization;国際化)の仕組みでそれは簡単にできる。

モデルの名前は翻訳ファイル(config/locale/*.yml)に

ja:
  activerecord:
    models:
      member: 会員

のように記述しておく。

そして,そうやって定義した「会員」という文字列を得るには,

t('activerecord.models.member')

とやるか,あるいは

Member.model_name.human

とやればよい。

model_name というのはモデルの名前に関する情報(クラス名の文字列,単数形/複数形,スネークケース等々)を持った ActiveModel::Name オブジェクトを返すメソッド。

ActiveModel::Name#human は,人間に見せるための文字列を作るメソッド。
例えば BlogPost モデルの場合,ロケールが英語なら "Blog post" という文字列を返す。
ロケールが日本語だったら,翻訳ファイルに従ってたとえば "ブログ投稿" という文字列を返す。

ここまでの話は過去にも Qiita で何度か取り上げられている。

もう一つの方法

ここから本記事のテーマ。

この model_name メソッドは,実はモデルオブジェクトでも使えるし,モデルオブジェクトのコレクションでも使うことができる。

つまり,例えば MembersControllershow アクションで

@member = Member.find(params[:id])

となっていたら,ビューで

@member.model_name.human

などと書ける。
同様に index アクションで

@members = Member.all

などとなっていたら,ビューで

@members.model_name.human

と書くことができる。

何が嬉しいの

しかし,Member.model_name を,あえて @members.model_name と書いて何が嬉しいのか。

嬉しい理由を一つだけ挙げてみる。

よく似たモデルがあって,同じような処理・表示を行う場合に,コードが合わせやすい,ということがあるのだ。

例えば法人会員モデル CorporateMember と個人会員モデル IndividualMember があるとする(英語が苦手なので,名前が適切かどうかは知らん)。
両者に同じような処理を書くのだが,持っているフィールドが違っているなどの理由で,一つのモデルにうまく統合できない,という場合を想定する。

index アクションはそれぞれこうなるだろうか?

corporate_members_controller.rb
def index
  @corporate_members = CorporateMember.all
end
individual_members_controller.rb
def index
  @individual_members = IndividualMember.all
end

いやいや,インスタンス変数は @corporate_members などではなく単に @members としたい。つまり

corporate_members_controller.rb
def index
  @members = CorporateMember.all
end
individual_members_controller.rb
def index
  @members = IndividualMember.all
end

だ。
これにより,ビューのコードが両者で同じように書ける。
こういうとき,①共通部分を部分テンプレートに括り出すか,②別々に書くか,二つの選択肢がある。どちらがいいかはケースバイケースだと思う。

②の場合でも,テンプレートが同じように書けていると,テキスト比較ツールで比較しやすい。
両テンプレートに同じような修正を施すとき,テキスト比較をすることで修正ミスや修正漏れに気付きやすくなる。

ここで本題に戻る。
テンプレートでモデル名を表示したいとき,

CorporateMember.model_name.human

などとせずに

@members.model_name.human

と書けば,この部分も共通化できる,というわけ。
これが嬉しい理由。

おまけ

ちなみに,human_attribute_name もモデルオブジェクトのコレクションに使うことができ,

@members.human_attribute_name :name # => "名前"

などと書ける。

しかしモデルオブジェクトには使えないので,

@member.human_attribute_name :name # => NoMethodError

などとは書けない。

19
12
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
19
12