やりたいこと
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
メソッドは,実はモデルオブジェクトでも使えるし,モデルオブジェクトのコレクションでも使うことができる。
つまり,例えば MembersController
の show
アクションで
@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
アクションはそれぞれこうなるだろうか?
def index
@corporate_members = CorporateMember.all
end
def index
@individual_members = IndividualMember.all
end
いやいや,インスタンス変数は @corporate_members
などではなく単に @members
としたい。つまり
def index
@members = CorporateMember.all
end
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
などとは書けない。