-
Notifications
You must be signed in to change notification settings - Fork 901
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issue 015/serializing postgres arrays #1018
Issue 015/serializing postgres arrays #1018
Conversation
module PaperTrail | ||
module AttributeSerializers | ||
# :nodoc: | ||
class ArraySerializer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really like the OO design you've gone with. It gives us some parts that we can understand independently.
Regarding the name, the intention of the AttributeSerializers
module is to "serialize" two attributes:
- object
- object_changes
There is no attribute named array
, so I think this is either:
- not the correct module to put this class in, or
- the module should be given a more generic name
My first instinct is the former, that this is not the correct module to put this class in. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point and I'd also lean towards no. 1.
Given that the original implementation obtains an AR serializer by calling #type_for_attribute(attr)
then perhaps PaperTrail::TypeSerializers::PostgresArraySerializer
would be a better name?
@@ -0,0 +1,28 @@ | |||
module PaperTrail | |||
module AttributeSerializers | |||
# :nodoc: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please provide documentation for all new classes.
create_table :postgres_users, force: true do |t| | ||
t.string :name | ||
t.integer :post_ids, array: true | ||
t.datetime :login_times, array: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like how you are testing two different types of arrays here. Also, it looks like this is the first test table to have arrays at all! Kind of surprising.
@@ -0,0 +1,37 @@ | |||
require "spec_helper" | |||
|
|||
RSpec.describe PaperTrail::AttributeSerializers::ObjectAttribute do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use the nested-module style.
module PaperTrail
module AttributeSerializers
RSpec.describe ObjectAttribute
spec/spec_helper.rb
Outdated
@@ -2,6 +2,7 @@ | |||
ENV["DB"] ||= "sqlite" | |||
|
|||
require "byebug" | |||
require "support/database_specific_specs" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please create a separate PR for this. It's a good idea, but I'd like to handle it separately, and more comprehensively. For this PR, please use plain ruby conditionals the way other tests currently do.
# with custom PaperTrail ones. | ||
module AttributeSerializer | ||
def self.for(klass, attr) | ||
case active_record_serializer = klass.type_for_attribute(attr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please do not use the assignment operator in a case
.
active_record_serializer.subtype, | ||
active_record_serializer.delimiter | ||
) | ||
else active_record_serializer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please move this onto its own line:
else
active_record_serializer
end
# not suited for JSON encoding. This factory | ||
# replaces certain default Active Record serializers | ||
# with custom PaperTrail ones. | ||
module AttributeSerializer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see what you were going for with this name. AttributeSerializer.for
does read nicely, but I'd think I'd prefer AttributeSerializerFactory.for
. It doesn't read as well, but you can tell the purpose of the module from its name alone.
# Values returned by some Active Record serializers are | ||
# not suited for JSON encoding. This factory | ||
# replaces certain default Active Record serializers | ||
# with custom PaperTrail ones. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A good, helpful comment. I'd change "JSON encoding" to "writing JSON to a text column.".
This phrasing disabiguates JSON-in-text-column from native postgres json(b).
@@ -32,15 +34,15 @@ def defined_enums | |||
# This implementation uses AR 5's `serialize` and `deserialize`. | |||
class CastAttributeSerializer | |||
def serialize(attr, val) | |||
@klass.type_for_attribute(attr).serialize(val) | |||
PaperTrail::AttributeSerializers::AttributeSerializer.for(@klass, attr).serialize(val) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not necessary to fully-qualify the constant here. AttributeSerializer
alone is sufficient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the comprehensive code review @jaredbeck! A lot of good points there, I have made changes as requested.
Thanks for your work on this Hubert! |
This PR addresses paper-trail-gem#1015 Starting from Rails version 5.0.2 the default serializer of PostgreSQL columns returns an ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array object instead of a string. This new object is not suitable for JSON encoding and breaks versioning of any array fields backed by Postgres. Whenever a PostgreSQL array is used, instead of asking Active Record for a serializer we introduce our own, which simply returns the underlying array without any modifications.
This PR addresses #1015
Starting from Rails version 5.0.2 the default serializer of PostgreSQL columns returns an
ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array
object instead of a string. This new object is not suitable for JSON encoding and breaks versioning of any array fields backed by Postgres.Whenever a PostgreSQL array is used, instead of asking Active Record for a serializer we introduce our own, which simply returns the underlying array without any modifications.