From 316f6f3c3eed458253c19e57e6893b277d1cafd4 Mon Sep 17 00:00:00 2001 From: Deron Meranda Date: Tue, 19 Apr 2016 02:12:46 -0400 Subject: [PATCH 1/3] Fix case-insensitivity uniqueness validation for MySQL. In MySQL individual columns can be case-insensitive, according to their collation type qualifier, without regard to any index. Rails already provides a case_sensitive? method on columns via the AbstractMysqlAdapter module. --- lib/schema_validations/active_record/validations.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/schema_validations/active_record/validations.rb b/lib/schema_validations/active_record/validations.rb index d76d93d..78e2232 100644 --- a/lib/schema_validations/active_record/validations.rb +++ b/lib/schema_validations/active_record/validations.rb @@ -169,7 +169,7 @@ def add_uniqueness_validation(column) #:nodoc: options = {} options[:scope] = scope if scope.any? options[:allow_nil] = true - options[:case_sensitive] = false if has_case_insensitive_index?(column, scope) + options[:case_sensitive] = false if column_is_case_insensitive?(column) or has_case_insensitive_index?(column, scope) options[:if] = (proc do |record| if scope.all? { |scope_sym| record.public_send(:"#{scope_sym}?") } record.public_send(:"#{column.name}_changed?") @@ -181,6 +181,10 @@ def add_uniqueness_validation(column) #:nodoc: validate_logged :validates_uniqueness_of, name, options end + def column_is_case_insensitive?(column) + column.respond_to?(:case_sensitive?) && ! column.case_sensitive? + end + def has_case_insensitive_index?(column, scope) indexed_columns = (scope + [column.name]).map(&:to_sym).sort index = column.indexes.select { |i| i.unique && i.columns.map(&:to_sym).sort == indexed_columns }.first From 89f54f032b98eeb582a925343c55c66fe84882a8 Mon Sep 17 00:00:00 2001 From: Deron Meranda Date: Tue, 19 Apr 2016 02:27:09 -0400 Subject: [PATCH 2/3] Only call the column's case_sensitive? if it is determined by the collation. When determining whether a uniqueness validation should be case insensitive, we only want to consider the column's own reported case-sensitivity if it is a true property of the column, i.e., due to its collation/character set. The schema_plus_columns gem monkey patches in its own version of case_sensitive?, for PostgreSQL, that determines this based upon the properties of ANY indexes in which the column participates. That method does NOT correctly take into account the index scope. Since in PostgreSQL it is possible to have a column participate in two indexes, one being case-sensitive and another being case-insensitive, it is important to always consider the scope. This does not matter with MySQL. --- lib/schema_validations/active_record/validations.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/schema_validations/active_record/validations.rb b/lib/schema_validations/active_record/validations.rb index 78e2232..d9be6d5 100644 --- a/lib/schema_validations/active_record/validations.rb +++ b/lib/schema_validations/active_record/validations.rb @@ -182,7 +182,7 @@ def add_uniqueness_validation(column) #:nodoc: end def column_is_case_insensitive?(column) - column.respond_to?(:case_sensitive?) && ! column.case_sensitive? + column.respond_to?(:collation) && column.respond_to?(:case_sensitive?) && ! column.case_sensitive? end def has_case_insensitive_index?(column, scope) From ac3ed285e88fbc0aa6279780547938b650a306d9 Mon Sep 17 00:00:00 2001 From: Deron Meranda Date: Tue, 19 Apr 2016 02:46:10 -0400 Subject: [PATCH 3/3] Readme should mention schema_plus_pg_indexes only needed for PostgreSQL. Old text implied case-insensitivity is only supported with that gem. But now MySQL case-insensitive validations will work without any extra gems. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9751ec7..e38ad60 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ Constraints: | `null: false` | `validates ... presence: true` | | `limit: 100` | `validates ... length: { maximum: 100 }` | | `unique: true` | `validates ... uniqueness: true` | -| `unique: true, case_sensitive: false`
(If [schema_plus_pg_indexes](https://github.com/SchemaPlus/schema_plus_pg_indexes) is also in use) | `validates ... uniqueness: { case_sensitive: false }` | +| `unique: true, case_sensitive: false`
(Requires [schema_plus_pg_indexes](https://github.com/SchemaPlus/schema_plus_pg_indexes) for PostgreSQL) | `validates ... uniqueness: { case_sensitive: false }` | Data types: