Skip to content

Commit

Permalink
Serialize postgres' hstore, json and array types correctly in AR upda…
Browse files Browse the repository at this point in the history
…te methods.

Fixes rails#12261. Closes rails#12395.

Conflicts:
	activerecord/CHANGELOG.md
	activerecord/test/cases/adapters/postgresql/array_test.rb
	activerecord/test/cases/adapters/postgresql/json_test.rb
  • Loading branch information
tadast authored and carlosantoniodasilva committed Dec 23, 2013
1 parent 5651009 commit 73bba4c
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 4 deletions.
7 changes: 7 additions & 0 deletions activerecord/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
* Fixed `update_column`, `update_columns`, and `update_all` to correctly serialize
values for `array`, `hstore` and `json` column types in `PostgreSQL`.

Fixes #12261.

*Tadas Tamosauskas*

* Do not consider PostgreSQL array columns as number or text columns.

The code uses these checks in several places to know what to do with a
Expand Down
9 changes: 5 additions & 4 deletions activerecord/lib/active_record/sanitization.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def sanitize_sql_hash_for_conditions(attrs, default_table_name = self.table_name
# # => "status = NULL , group_id = 1"
def sanitize_sql_hash_for_assignment(attrs, table)
attrs.map do |attr, value|
"#{connection.quote_table_name_for_assignment(table, attr)} = #{quote_bound_value(value)}"
"#{connection.quote_table_name_for_assignment(table, attr)} = #{quote_bound_value(value, connection, columns_hash[attr.to_s])}"
end.join(', ')
end

Expand Down Expand Up @@ -152,15 +152,16 @@ def replace_named_bind_variables(statement, bind_vars) #:nodoc:
end
end

def quote_bound_value(value, c = connection) #:nodoc:
if value.respond_to?(:map) && !value.acts_like?(:string)
def quote_bound_value(value, c = connection, column = nil) #:nodoc:
db_native_type = column && (column.respond_to?(:array) && column.array || [:json, :hstore].include?(column.type) )
if value.respond_to?(:map) && !value.acts_like?(:string) && !db_native_type
if value.respond_to?(:empty?) && value.empty?
c.quote(nil)
else
value.map { |v| c.quote(v) }.join(',')
end
else
c.quote(value)
c.quote(value, column)
end
end

Expand Down
6 changes: 6 additions & 0 deletions activerecord/test/cases/adapters/postgresql/array_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,12 @@ def test_attribute_for_inspect_for_array_field
assert_equal("[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...]", record.attribute_for_inspect(:ratings))
end

def test_update_all
PgArray.create! tags: ["one", "two", "three"]
PgArray.update_all tags: ["four", "five"]
assert_equal ["four", "five"], PgArray.first.tags
end

private
def assert_cycle field, array
# test creation
Expand Down
6 changes: 6 additions & 0 deletions activerecord/test/cases/adapters/postgresql/hstore_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,12 @@ def test_quoting_special_characters
def test_multiline
assert_cycle("a\nb" => "c\nd")
end

def test_update_all
Hstore.create! tags: { "one" => "two" }
Hstore.update_all tags: { "three" => "four" }
assert_equal({ "three" => "four" }, Hstore.first.tags)
end
end

private
Expand Down
6 changes: 6 additions & 0 deletions activerecord/test/cases/adapters/postgresql/json_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,10 @@ def test_with_store_accessors
x = JsonDataType.first
assert_equal "640×1136", x.resolution
end

def test_update_all
JsonDataType.create! payload: { "one" => "two" }
JsonDataType.update_all payload: { "three" => "four" }
assert_equal({ "three" => "four" }, JsonDataType.first.payload)
end
end

0 comments on commit 73bba4c

Please sign in to comment.