Ruby on Railsを使った開発をしていると「システムのER図が欲しい」といったお願いされることがあります。
Railsを使っているのであれば、rails-erd というRubyGemを使うことで簡単にER図を出力できます。
rails-erdで出力されるER図はEntityもAttributeも全て英語です。
提出先がエンジニアである場合や、普段からモデル名を使ったコミュニケーションをしている場合であればこのままでもなんとかなるかもしれません。
一方、相手がビジネスサイドのメンバーである場合や、普段はモデルを日本語変換してコミュニケーションしている相手の場合はこのER図をそのまま出しても困惑されてしまいます。
そこで、今回はなんとかしてEntity・Attributeを日本語化できないか検討しました。結論とそこに至った過程をメモしておきます。
結論
結論としては、rails-erd
の下記ファイルを直接編集することで日本語化することができました。
Railsのi18nに対応して、モデル名やカラム名の日本語化に対応していることが前提ですのでご注意ください。
変更ファイル
変更点
<% if options.orientation == :horizontal %>{<% end %>
<table border="0" align="center" cellspacing="0.5" cellpadding="0" width="<%= NODE_WIDTH + 4 %>">
- <tr><td align="center" valign="bottom" width="<%= NODE_WIDTH %>"><font face="<%= FONTS[:bold] %>" point-size="11"><%= entity.name %></font></td></tr>
+ <tr><td align="center" valign="bottom" width="<%= NODE_WIDTH %>"><font face="<%= FONTS[:bold] %>" point-size="11"><%= entity.model.model_name.human %></font></td></tr>
</table>
<% if attributes.any? %>
|
<table border="0" align="left" cellspacing="2" cellpadding="0" width="<%= NODE_WIDTH + 4 %>">
<% attributes.each do |attribute| %>
- <tr><td align="left" width="<%= NODE_WIDTH %>" port="<%= attribute %>"><%= attribute.name %> <font face="<%= FONTS[:italic] %>" color="grey60"><%= attribute.type_description %></font></td></tr>
+ <tr><td align="left" width="<%= NODE_WIDTH %>" port="<%= attribute %>"><%= entity.model.human_attribute_name(attribute.name) %> <font face="<%= FONTS[:italic] %>" color="grey60"><%= attribute.type_description %></font></td></tr>
<% end %>
</table>
<% else %>
結論に至るまでの過程
rails-erd以外の既存ツールを検討
DBスキーマを出力するツールは rails-erd
に限らずいくつか存在します。それらのツールを使うことで簡単に解決ができないか検討しました。
しかし、多くのツールにおいて、日本語化をするためにはDBスキーマの物理名と論理名(日本語)の対応付けを別途行う必要があります。
Railsで作られたアプリであれば大抵の場合、i18nで既に日本語定義を終えているはずなので、日本語のER図を出すためだけに再度対応付けを行うのは避けたいところです。
このため、やはり rails-erd
を用いてER図を出力する方向で検討することにしました。
rails-erdにおいてER図のEntity・Attributeに該当する箇所を探す
ファイル名からあたりを付けつつ、適宜 binding.debugger
を埋め込んでコマンドを実行してみることで、出力を行っているファイルを見つけ出します。
今回の場合は、前述の通り rails_erd/diagram/templates/node.html.erb
というERBファイルにたどり着きました。
ERBファイル内で参照できる変数・その変数メソッドを探る
このERBファイルを読んで、使えそうな変数を見つけます。 entity
や attribute
という変数が存在するので、これらは使えそうということがわかります。
このERBファイル内に <%= binding.debugger %>
を埋め込んで、 entity
や attribute
がどのクラスのオブジェクトなのか確認します。
entity.class.name #=> "RailsERD::Domain::Entity"
attributes.class.name #=> "Array"
attributes.first.class.name #=> "RailsERD::Domain::Attribute"
namescopeをたどると、EntityとAttributeは次のファイルに定義されているクラスのインスタンスであることがわかります。
このうち、 entity.rb
には model
という attr_reader
が定義されているので、これがおそらくActiveRecordのインスタンスだろうと推測しました。実際に試してみます。
entity.model #=> ActiveStorage::Attachment(id: integer, name: string, record_type: string, record_id: integer, blob_id: integer, created_at: datetime)
# 何回かcontinueして再度実施
entity.model #=> Announcement(id: integer, title: string, body: text, created_at: datetime, updated_at: datetime)
たまたま最初のクラスが ActiveStorage::Attachment
だったので、何回かcontinueすることで entity
に入るオブジェクトがActiveRecordのインスタンスとなることを確認できました。
あとはRailsのi18n機能のメソッドを使うことで日本語化できます。
おわりに
今回は、RubyGemの中身を読み解いてソースコードを一部変更することで目的を達成しました。
できればPull Requestを出して、コマンドオプション等で簡単に出力モードを切り替えられるようにできるとより便利なのですが、それは時間のある時に対応したいと思います。