Permalink
Browse files

Scopes can be array columns for uniq. validator

`validates_uniqueness_of` would blow up when used with a scope that was
an array column. The validator must perform a query to determine whether
the record already exists in the database, and uses the scope to do so.
When it constructs the query, it deserializes the value of the scope (an
array). Unfortunately this breaks the query because Postgres is still
expecting that value to be an array. There is a newer version of Arel
that prevents this from happening, but 4.1 is not on that version, so we
have to emulate that code here.
  • Loading branch information...
mcmire committed Feb 13, 2015
1 parent 2fd126a commit d47801b8cb06a28c97ce31d2cd81fc5e1e24ee02
@@ -81,7 +81,13 @@ def scope_relation(record, table, relation)
else
scope_value = record.read_attribute(scope_item)
end
relation = relation.and(table[scope_item].eq(scope_value))
# This is basically emulating an Arel::Nodes::Casted
column = record.class.columns_hash[scope_item.to_s]
quoted_value = record.class.connection.quote(scope_value, column)
node = Arel::Nodes::SqlLiteral.new(quoted_value)
relation = relation.and(table[scope_item].eq(node))
end
relation
@@ -45,6 +45,11 @@ class UniquenessValidationTest < ActiveRecord::TestCase
repair_validations(Topic, Reply)
class ModelWithScopedValidationOnArray < ActiveRecord::Base
self.table_name = 'postgresql_arrays'
validates_uniqueness_of :name, scope: [:commission_by_quarter]
end
def test_validate_uniqueness
Topic.validates_uniqueness_of(:title)
@@ -388,6 +393,15 @@ def test_validate_uniqueness_with_array_column
assert e2.errors[:nicknames].any?, "Should have errors for nicknames"
assert_equal ["has already been taken"], e2.errors[:nicknames], "Should have uniqueness message for nicknames"
end
def test_validate_uniqueness_scoped_to_array
record = ModelWithScopedValidationOnArray.new(
name: "Sheldon Cooper",
commission_by_quarter: [1, 2, 3]
)
assert_nothing_raised { record.valid? }
end
end
def test_validate_uniqueness_on_existing_relation
@@ -62,7 +62,8 @@
CREATE TABLE postgresql_arrays (
id SERIAL PRIMARY KEY,
commission_by_quarter INTEGER[],
nicknames TEXT[]
nicknames TEXT[],
name TEXT
);
_SQL

0 comments on commit d47801b

Please sign in to comment.