Edited at

typusでActiveRecord::enumに合わせる方法

More than 1 year has passed since last update.

rails4.1からActiveRecord::Enumが採用されて、困ったことになった。

Typusの標準でつけていた、セレクトボックスの機能に対しては、モデルにstatusesの様に、カラム名の複数形で選択肢の名前を記述させる仕様が、ActiveRecord::Enumの仕様と被ってしまった。

どうやって、この問題をなるべく綺麗に回避しようかと考えた結果の自分なりのログです。


enum_helpを導入する

他のgemだと、rails admin、active adminそれぞれで、カラム名にひと単語加えたエイリアスを貼ったりする方法で管理をしていた。

そもそも、railsが標準でenumを導入したのに、そのi18nの方法は全く手をつけないでしまったのが、railsコミュニティ死ね!と言いたくなる片手落ちの解決方法なのですが、現実策としては、i18nを拡張するgemを採用して、それに合わせてtypusをカスタマイズしてしまう方法でした。

簡単に検索した結果、enum_helpの評判が良さそうなのでそのまま採用してカスタマイズした結果、案外よく動いてしまったので、反芻することなくそのまま使ってしまっています。

https://rubygems.org/gems/enum_help/

まずは、gemfileに記述を行なって、bundle install

gem "enum_help"

これで、カラム名にi18nを付ければi18nが行われる様になりました。

class User < ActiveRecord::Base

enum status: { retired: 0, entried: 1 }
end

User.statuses_i18n # {"retired"=>"退会済", "entried"=>"入会中"}
user.status_i18n # 入会中

あとは、i18nに対応しているメソッドがあるときはそれを実行する様に、typusの内側を書き換えてあげるだけです。

以下のコードをapp/helpers/admin/resources/data_types/selector_helper.rbというテキストファイルに貼り付けてください。typusの既存の機能を上書きして、先に_i18nが付いているメソッドを探して実行する様になります。


app/helpers/admin/resources/data_types/selector_helper.rb

module Admin::Resources::DataTypes::SelectorHelper

def table_selector_field(attribute, item)
item.try("#{attribute.to_s}_i18n") || item.mapping(attribute)
end

def display_selector(item, attribute)
item.try("#{attribute.to_s}_i18n") || item.mapping(attribute)
end
end


同じ様に編集画面で作成するセレクトボックスも、以下のコードを作成して、_i18nの付いたメソッドを先に探す様に、既存の機能を上書きしてしまいます。


app/views/admin/templates/_selector.html.erb

<%

custom = { :rows => @resource.typus_options_for(:form_rows) }
options = options.merge!(custom)
%>
<div class="control-group" id="<%= attribute_id %>">
<%= form.label attribute, label_text, { :class => "control-label" } %>
<div class="controls">
<% if attribute=="role" and admin_user.role!="admin" %>
<% html_options.merge!(disabled: true) %>
<%= form.select attribute, @resource.send(attribute.pluralize), options, html_options %>
<% else %>
<%= form.select attribute, @resource.try("#{attribute.pluralize}_i18n").try(:invert) || @resource.send(attribute.pluralize), options, html_options %> <% end %>
</div>
</div>

これで、i18nの付いた、セレクトボックスを再現出来ました。

スクリーンショット 2017-01-05 17.58.13.png

2ファイルを上書きするだけで、i18nを実現出来たので、typus標準に組み込んでしまいたいのですが、typus自体は、必要最小限のgem以外は取り込まない方針なのでなかなか難しいのでしょうね。