From f6ec9bbeea2bc384929c97f8b2c1cd5dff4da20f Mon Sep 17 00:00:00 2001 From: Donal McBreen Date: Wed, 12 Nov 2025 17:16:07 +0000 Subject: [PATCH] Use a custom class for Uuid values --- config/initializers/uuid_primary_keys.rb | 2 +- lib/rails_ext/active_record_uuid_type.rb | 25 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/config/initializers/uuid_primary_keys.rb b/config/initializers/uuid_primary_keys.rb index 01a1625fa..a3827ab13 100644 --- a/config/initializers/uuid_primary_keys.rb +++ b/config/initializers/uuid_primary_keys.rb @@ -10,7 +10,7 @@ ActiveSupport.on_load(:active_record) do end def quote(value) - if value.is_a?(String) && value.encoding == Encoding::BINARY && value.bytesize == 16 + if value.is_a?(ActiveRecord::Type::UuidValue) # Convert binary UUIDs to hex literals to avoid encoding conflicts in SQL strings "X'#{value.unpack1('H*')}'" else diff --git a/lib/rails_ext/active_record_uuid_type.rb b/lib/rails_ext/active_record_uuid_type.rb index 46ff73017..2278744fb 100644 --- a/lib/rails_ext/active_record_uuid_type.rb +++ b/lib/rails_ext/active_record_uuid_type.rb @@ -1,6 +1,30 @@ # Custom UUID attribute type for MySQL binary storage with base36 string representation module ActiveRecord module Type + # Wrapper class to distinguish UUID binary values from regular binary strings + class UuidValue + def initialize(binary_string) + @value = binary_string + end + + def to_s + @value + end + + # Delegate methods needed for SQL quoting + def unpack1(format) + @value.unpack1(format) + end + + def bytesize + @value.bytesize + end + + def encoding + @value.encoding + end + end + class Uuid < Binary BASE36_LENGTH = 25 # 36^25 > 2^128 @@ -16,6 +40,7 @@ module ActiveRecord hex = value.to_s.to_i(36).to_s(16).rjust(32, "0") binary = hex.scan(/../).map(&:hex).pack("C*") binary.force_encoding(Encoding::BINARY) + UuidValue.new(binary) end def deserialize(value)