(wat-aro)

生きてます

ActiveModel::Attributesでカスタムタイプを使う

Rails 5.2.0 で入ったActiveModel::Attributes API 最高ですよね。

でもカスタムタイプのドキュメントが見つからないんですよね。 ActiveRecord::Attributes API のカスタムタイプ ならあるのですが。

ソースコード見たところ簡単に作れるのがわかったので紹介します。

まず型の登録部分ですが、lib/active_model/type.rb で定義されています。

また、ActiveModelで使われているデフォルトタイプの実装を見ると cast_value メソッドがあればよさそうです。

ActiveRecord::Attributes API と同様に実装します。

class MoneyType < ActiveModel::Type::Integer
  def cast_value(value)
    if !value.kind_of?(Numeric) && value.include?('$')
      price_in_dollars = value.gsub(/\$/, '').to_f
      super(price_in_dollars * 100)
    else
      super
    end
  end
end

# config/initializers/types.rb
ActiveModel::Type.register(:money, MoneyType)

# app/models/store_listing.rb
class StoreListing
  include ActiveModel::Model
  include ActiveModel::Attributes

  attribute :price_in_cents, :money
end

store_listing = StoreListing.new(price_in_cents: '$10.00')
store_listing.price_in_cents # => 1000

このように ActiveModel::Attributes でカスタムタイプを使うことができます。