Repository: rails/rails
File: activerecord/lib/active_record/attribute_methods/serialization.rb (Ruby)

Code before:

          column_serializer = build_column_serializer(attr_name, coder, type, { yaml: yaml, json: json })

          attribute(attr_name, **options)

          decorate_attributes([attr_name]) do |attr_name, cast_type|
            if type_incompatible_with_serialize?(cast_type, coder, type)
              raise ColumnNotSerializableError.new(attr_name, cast_type)
            end

            cast_type = cast_type.subtype if Type::Serialized === cast_type
            Type::Serialized.new(cast_type, column_serializer, comparable: comparable)
          end
        end

        private
          def build_column_serializer(attr_name, coder, type, options = {})
            # When ::JSON is used, force it to go through the Active Support JSON encoder
            # to ensure special objects (e.g. Active Record models) are dumped correctly
            # using the #as_json hook.
            coder = Coders::JSON if coder == ::JSON

            if coder == ::YAML || coder == Coders::YAMLColumn
              Coders::YAMLColumn.new(attr_name, type, **(options[:yaml] || {}))
            elsif coder == Coders::JSON
              Coders::JSON.new(**(options[:json] || {}))
            elsif coder.respond_to?(:new) && !coder.respond_to?(:load)
              coder.new(attr_name, type)
            elsif type && type != Object
              Coders::ColumnSerializer.new(attr_name, coder, type)
            else
              coder
            end
          end

          def type_incompatible_with_serialize?(cast_type, coder, type)
            cast_type.is_a?(ActiveRecord::Type::Json) && coder == ::JSON ||
              cast_type.respond_to?(:type_cast_array, true) && type == ::Array
          end
      end
    end
  end
end


Review comment (suggestion):
If this method accepted keyword arguments instead of a `Hash`, this could be simplified:

```suggestion
              Coders::YAMLColumn.new(attr_name, type, yaml)
            elsif coder == Coders::JSON
              Coders::JSON.new(json)
```

Code after:

          column_serializer = build_column_serializer(attr_name, coder, type, yaml)

          attribute(attr_name, **options)

          decorate_attributes([attr_name]) do |attr_name, cast_type|
            if type_incompatible_with_serialize?(cast_type, coder, type)
              raise ColumnNotSerializableError.new(attr_name, cast_type)
            end

            cast_type = cast_type.subtype if Type::Serialized === cast_type
            Type::Serialized.new(cast_type, column_serializer, comparable: comparable)
          end
        end

        private
          def build_column_serializer(attr_name, coder, type, yaml = nil)
            # When ::JSON is used, force it to go through the Active Support JSON encoder
            # to ensure special objects (e.g. Active Record models) are dumped correctly
            # using the #as_json hook.

            if coder == ::YAML || coder == Coders::YAMLColumn
              Coders::YAMLColumn.new(attr_name, type, **(yaml || {}))
            elsif coder == ::JSON || coder == Coders::JSON
              Coders::JSON.new
            elsif coder.respond_to?(:new) && !coder.respond_to?(:load)
              coder.new(attr_name, type)
            elsif type && type != Object
              Coders::ColumnSerializer.new(attr_name, coder, type)
            else
              coder
            end
          end

          def type_incompatible_with_serialize?(cast_type, coder, type)
            cast_type.is_a?(ActiveRecord::Type::Json) && coder == ::JSON ||
              cast_type.respond_to?(:type_cast_array, true) && type == ::Array
          end
      end
    end
  end
end