Rails’ Attribute API allows you to define custom attribute types with their own serialization and type casting logic, even for non-database backed attributes:
class Money < ActiveRecord::Type::Integer
def cast(value)
return super if value.kind_of?(Integer)
return super(value.gsub(/[$,]/, '').to_i) if value.is_a?(String)
super
end
end
# Register the custom type
ActiveRecord::Type.register(:money, Money)
class Product < ApplicationRecord
# Use the custom type for a database column
attribute :price, :money
# Or create a virtual attribute with type casting
attribute :sale_price, :money, default: 0
end
product = Product.new(price: "$10,000")
product.price # => 10000
This is incredibly useful for handling non-primitive data types consistently throughout the application.