1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Attempt to maintain encoding for arrays of strings with PG

I still think that this is something that should be handled in the pg
gem, but it's not going to end up happening there so we'll do it here
instead. Once we bump to pg 0.19 we can pass the encoding to the
`encode` method instead.

This issue occurs because C has no concept of encoding (or strings,
really). The bytes that we pass here when sending the value to the
database will always be interpreted as whatever encoding the connection
is currently configured to use. That means that roundtripping to the
database will lose no information

However, after assigning we round trip through our type system without
hitting the database. The only way that we can do the "correct" thin
here would be to actually give a reference to the connection to the
array type and have it check the current value of the connection's
encoding -- which I'm strongly opposed to. We could also pass in the
encoding when it's constructed, but since that can change independently
of the type I'm not a huge fan of that either.

This feels like a reasonable middle ground, where if we have an array of
strings we simply use the encoding of the string we're given.

Fixes #26326.
This commit is contained in:
Sean Griffin 2016-08-31 12:06:30 -04:00
parent 03d3f036a7
commit 7ba3a48df5
3 changed files with 25 additions and 1 deletions

View file

@ -1,3 +1,10 @@
* PostgreSQL array columns will now respect the encoding of strings contained
in the array.
Fixes #26326.
*Sean Griffin*
* Inverse association instances will now be set before `after_find` or
`after_initialize` callbacks are run.

View file

@ -33,7 +33,11 @@ module ActiveRecord
def serialize(value)
if value.is_a?(::Array)
@pg_encoder.encode(type_cast_array(value, :serialize))
result = @pg_encoder.encode(type_cast_array(value, :serialize))
if encoding = determine_encoding_of_strings(value)
result.encode!(encoding)
end
result
else
super
end
@ -63,6 +67,13 @@ module ActiveRecord
@subtype.public_send(method, value)
end
end
def determine_encoding_of_strings(value)
case value
when ::Array then determine_encoding_of_strings(value.first)
when ::String then value.encoding
end
end
end
end
end

View file

@ -311,6 +311,12 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase
assert_equal ["has already been taken"], e2.errors[:tags], "Should have uniqueness message for tags"
end
def test_encoding_arrays_of_utf8_strings
string_with_utf8 = "nový"
assert_equal [string_with_utf8], @type.deserialize(@type.serialize([string_with_utf8]))
assert_equal [[string_with_utf8]], @type.deserialize(@type.serialize([[string_with_utf8]]))
end
private
def assert_cycle(field, array)
# test creation