前段
enum layout: { list: 0, grid: 1 }
上記のような top_layout
が integer
のような enum があったとして、それを top_layout
という名前に変えたいとします。(カラムのリネームが一番良いというのは置いておいて)
アプリケーションで扱う上では、以下のように alias_attribute
と enum
の変更で事足りました。
alias_attribute :top_layout, :layout
enum top_layout: { list: 0, grid: 1 }
一方で、 rails_admin
が生成する UI の方は依然として layout
が表示され、 top_layout
が現れません。
rails_admin が ActiveRecord の属性をどう取得しているか
module RailsAdmin
module Adapters
module ActiveRecord
def properties
columns = model.columns.reject do |c|
c.type.blank? ||
DISABLED_COLUMN_TYPES.include?(c.type.to_sym) ||
c.try(:array)
end
columns.collect do |property|
Property.new(property, model)
end
end
ざっと見ただけなので、他にも関連する要素はあるかもしれませんが、この properties で生成されたものをベースに扱っているように見えます。
これを確認したい場合には、console を開いて以下で確認できます。
> c = RailsAdmin.config(SampleModel.first)
> c.abstract_model.properties
当然 columns を取得されると、 alias_attribute
したところでどうしようもないです。
カスタマイズする
RailsAdmin.config do |config|
config.model SampleModel do
include_all_fields
exclude_fields :layout
field :top_layout, :active_record_enum
end
Wiki に従い、無効にしたい layout
を exlude_fields
に入れ、新たに入れたい top_layout
を追加し、 active_record_enum
として登録しました。
これで、通常の enum カラムと同じように表示されるようになります。
更新時に失敗する
このままだと、更新時になぜか 0
, 1
といった値が、 enum の値として認識されず、「'0'
のような値は enum には存在しない」といったエラーが出てしまいます。
ここに関しては以下が関わっています。
module RailsAdmin
module Config
module Fields
module Types
class ActiveRecordEnum < Enum
def parse_input_value(value)
abstract_model.model.attribute_types[name.to_s].deserialize(value)
end
この abstract_model.model
でアプリケーション側のモデル(例えば SampleModel
)を参照しているので、 attribute_types
は SampleModel.attribute_types
などすれば確認できます。
確認するとわかりますが、alias_attribute
するだけでは、この一覧に top_layout
は入ってきません。よって、ここでの deserialize は何も変化がなく、リクエストパラメーターとして送信された '0'
という文字列がそのまま assign_attributes
に渡されてしまい、上述のエラーになってしまいます。
attribute を定義する
attribute :top_layout, :integer
このような形で top_layout
も attribute として定義を追加します。ここは ActiveRecord::Enum::EnumType
を直接指定できるような type を与えたいところですが、それはできないので integer
にします。これは、もともとの layout
の型と同じです。
ここで attribute_types を実行するとわかりますが、alias_attribute 後も layout は ActiveRecord::Enum::EnumType として存在し続け、 top_layout は integer として定義されたような形になります。top_layout の enum 定義が、そのまま alias のオリジナルの layout の方にかかる形になるようです。
これで、更新時にも値の型変換が行われるようになったため、更新も問題なくできるようになりました。