aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
authorSean Griffin <sean@thoughtbot.com>2014-06-17 17:05:34 -0600
committerSean Griffin <sean@thoughtbot.com>2014-06-17 17:47:57 -0600
commitba29c28a47c8a8016f32cad8b7fcc6dbd0e06162 (patch)
tree97d739d6a0ae02ca88d18586c7ba8fdf2f6e0b95 /activerecord
parent7f7e2f12ab835526c6914843b983619ed12c9b68 (diff)
downloadrails-ba29c28a47c8a8016f32cad8b7fcc6dbd0e06162.tar.gz
rails-ba29c28a47c8a8016f32cad8b7fcc6dbd0e06162.tar.bz2
rails-ba29c28a47c8a8016f32cad8b7fcc6dbd0e06162.zip
Detect mutations of arrays and array members
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/CHANGELOG.md4
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb26
-rw-r--r--activerecord/test/cases/adapters/postgresql/array_test.rb23
3 files changed, 41 insertions, 12 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index fc726d6519..823597fc92 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,7 @@
+* Detect in-place modifications of PG array types
+
+ *Sean Griffin*
+
* Add `bin/rake db:purge` task to empty the current database.
*Yves Senn*
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
index 63f3be45de..d322c56acc 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
@@ -3,6 +3,20 @@ module ActiveRecord
module PostgreSQL
module OID # :nodoc:
class Array < Type::Value
+ include Type::Mutable
+
+ # Loads pg_array_parser if available. String parsing can be
+ # performed quicker by a native extension, which will not create
+ # a large amount of Ruby objects that will need to be garbage
+ # collected. pg_array_parser has a C and Java extension
+ begin
+ require 'pg_array_parser'
+ include PgArrayParser
+ rescue LoadError
+ require 'active_record/connection_adapters/postgresql/array_parser'
+ include PostgreSQL::ArrayParser
+ end
+
attr_reader :subtype, :delimiter
delegate :type, to: :subtype
@@ -31,18 +45,6 @@ module ActiveRecord
end
end
- # Loads pg_array_parser if available. String parsing can be
- # performed quicker by a native extension, which will not create
- # a large amount of Ruby objects that will need to be garbage
- # collected. pg_array_parser has a C and Java extension
- begin
- require 'pg_array_parser'
- include PgArrayParser
- rescue LoadError
- require 'active_record/connection_adapters/postgresql/array_parser'
- include PostgreSQL::ArrayParser
- end
-
private
def type_cast_array(value, method)
diff --git a/activerecord/test/cases/adapters/postgresql/array_test.rb b/activerecord/test/cases/adapters/postgresql/array_test.rb
index 15901b389e..266592e2c7 100644
--- a/activerecord/test/cases/adapters/postgresql/array_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/array_test.rb
@@ -16,6 +16,7 @@ class PostgresqlArrayTest < ActiveRecord::TestCase
t.string 'tags', array: true
t.integer 'ratings', array: true
t.datetime :datetimes, array: true
+ t.hstore :hstores, array: true
end
end
@column = PgArray.columns_hash['tags']
@@ -221,6 +222,28 @@ class PostgresqlArrayTest < ActiveRecord::TestCase
assert_equal %({hello,;"world;"}), semicolon_delim.type_cast_for_database(strings)
end
+ def test_mutate_array
+ x = PgArray.create!(tags: %w(one two))
+
+ x.tags << "three"
+ x.save!
+ x.reload
+
+ assert_equal %w(one two three), x.tags
+ assert_not x.changed?
+ end
+
+ def test_mutate_value_in_array
+ x = PgArray.create!(hstores: [{ a: 'a' }, { b: 'b' }])
+
+ x.hstores.first['a'] = 'c'
+ x.save!
+ x.reload
+
+ assert_equal [{ 'a' => 'c' }, { 'b' => 'b' }], x.hstores
+ assert_not x.changed?
+ end
+
def test_datetime_with_timezone_awareness
tz = "Pacific Time (US & Canada)"