Ask A Question


You’re not receiving notifications from this thread.

Custom Attribute Serializers with ActiveRecord in Rails Discussion

This feels much simpler for custom value objects and surprisingly more straightforward than the official way, i.e. registering a new Active Model type.

Great video, thank you.


What is the datatype of the price column in event table?


Chris, could you make a video comparing serialize (that you demonstrated here) vs attribute with a custom type (ActiveRecord::Type) vs using composed_of?


That is a great idea. I will definitely do that. 👍


Hello Chris, In which ruby and rails version, this custom attribute sanitizer is supported?


While this may be obvious, but the serialize method can take 2 types of argument - a class (like Array) or a coder (as coder: CoderClass).

For a custom class coder option is necessary. Additionally, the coder Class needs to be added to Rails.application.config.active_record.yaml_column_permitted_classes during the initialization, unless Rails.application.config.active_record.use_yaml_unsafe_load is used (which is not ideal.)


When I deal with currency amounts, I always store the amount in the DB as cents and then use some custom methods to generate "_in_dollars" methods that I use on my forms, because most people prefer to write "$1,234.56" dollars instead of "123456" cents.

For my simple currency uses, I think I prefer formatting methods, but if I needed to extract an actual object that I could run methods on from the value, then serialize would make more sense to me.

I've used this model concern for years to handle currency that I store as cents in the DB but my users want to interact with it as dollars:

# app/models/concerns/formatted_currency_in_dollars.rb
module FormattedCurrencyInDollars
  extend ActiveSupport::Concern

  included do
    def self.formatted_currency_in_dollars(model_attribute)
      model_attribute = model_attribute.to_s

      if model_attribute.ends_with?("_in_cents")
        model_attribute = model_attribute.delete_suffix("_in_cents")

      puts model_attribute

      # Getter (cents / 100.0)
      define_method("#{model_attribute}_in_dollars") do
        cents = send("#{model_attribute}_in_cents")
        return nil if cents.blank?
        value = (cents.to_f / 100.0)
        ("%.2f" % value) # Force 2 spaces to right of decimal

      # Setter (dollars * 100.0)
      define_method("#{model_attribute}_in_dollars=") do |value|
        cents = (value.blank? ? nil : (value.to_s.gsub(/[^0-9.\-]/, "").to_f * 100)).to_i
        send("#{model_attribute}_in_cents=", cents)

It assumes you have a DB column named "_in_cents", and it will create the getter/setter for the "_in_dollars". I prefer to be very explicit and store the "_in_cents" on my DB column, so that there's no confusion about what value is in the DB. If you were just looking at the DB values, and you saw "price" and the value was "200", is that "2.00 dollars" or "200 dollars"? Being explicit in situations like this avoids any confusion.

Join the discussion
Create an account Log in

Want to stay up-to-date with Ruby on Rails?

Join 79,047+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.

    Screencast tutorials to help you learn Ruby on Rails, Javascript, Hotwire, Turbo, Stimulus.js, PostgreSQL, MySQL, Ubuntu, and more.

    © 2023 GoRails, LLC. All rights reserved.