Is it possible to override default database types?

I want to override the default rails string type to always strip inputs. I’m aware there are multiple gems which solve this problem, but I felt a custom type is cleaner (while these gems rely on callbacks).

Following documentation I put the following in an initializer:

class StrippedStringType < ActiveRecord::Type::String
  def cast(value)
    super&.strip
  end
end

ActiveRecord::Type.register(:string, StrippedStringType, adapter: :postgresql)

and ActiveRecord::Type.lookup(:string) returns StrippedStringType, however my models still use ActiveModel::Type::String (which I could inspect by calling eg. User.attribute_types["first_name"]).

What’s also a bit weird: as per documentation I expected ActiveRecord::Type.register(:string, ...) to raise an error when called without :override, as we are overriding a native type, but no such thing happened.

Does anyone have any experience with this kind of thing?

I’m not an expert in the Attributes API, but I think it’s not working because you haven’t told your model to use it. It’s likely just picking ActiveRecord::Type::String based on db introspection.

Does it work if you explicitly tell your models to use the new type?

class SomeModel < ApplicationRecord
   attribute :some_attribute, StrippedStringType.new
   attribute :another_attribute, StrippedStringType.new
end

Yes that would work - however I want this to be picked up automatically, as it affects every :string-column in my app, and I don’t want to define this manually in every model for every :string-column. (That’s what we did in the past, and often forgot)

Monkeypatching ActiveModel::Type::String does what I want, but that seems a bit intrusive.

Overriding the default :string-type is exactly what I want in this case, but it seems I’m misunderstanding the purpose of overriding a type.

I have found a type map in the connection adapter (https://github.com/rails/rails/blob/2ed58965fd1072d12e68671f32e9d79a5151b43c/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb#L655-L686), so I maybe the types are picked there, without looking at ActiveRecord::Type?