Module: ActiveRecord::Validations::ClassMethods
- Defined in:
- lib/account_scopper.rb
Instance Method Summary collapse
-
#validates_global_uniqueness_of(*attr_names) ⇒ Object
Allow to validates uniqueness without scoping to the current account.
Instance Method Details
#validates_global_uniqueness_of(*attr_names) ⇒ Object
Allow to validates uniqueness without scoping to the current account.
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/account_scopper.rb', line 62 def validates_global_uniqueness_of(*attr_names) configuration = { :case_sensitive => true } configuration.update(attr_names.) validates_each(attr_names,configuration) do |record, attr_name, value| # The check for an existing value should be run from a class that # isn't abstract. This means working down from the current class # (self), to the first non-abstract class. Since classes don't know # their subclasses, we have to build the hierarchy between self and # the record's class. class_hierarchy = [record.class] while class_hierarchy.first != self class_hierarchy.insert(0, class_hierarchy.first.superclass) end # Now we can work our way down the tree to the first non-abstract # class (which has a database table to query from). finder_class = class_hierarchy.detect { |klass| !klass.abstract_class? } column = finder_class.columns_hash[attr_name.to_s] if value.nil? comparison_operator = "IS ?" elsif column.text? comparison_operator = "#{connection.case_sensitive_equality_operator} ?" value = column.limit ? value.to_s.mb_chars[0, column.limit] : value.to_s else comparison_operator = "= ?" end sql_attribute = "#{record.class.quoted_table_name}.#{connection.quote_column_name(attr_name)}" if value.nil? || (configuration[:case_sensitive] || !column.text?) condition_sql = "#{sql_attribute} #{comparison_operator}" condition_params = [value] else condition_sql = "LOWER(#{sql_attribute}) #{comparison_operator}" condition_params = [value.mb_chars.downcase] end if scope = configuration[:scope] Array(scope).map do |scope_item| scope_value = record.send(scope_item) condition_sql << " AND " << attribute_condition("#{record.class.quoted_table_name}.#{scope_item}", scope_value) condition_params << scope_value end end unless record.new_record? condition_sql << " AND #{record.class.quoted_table_name}.#{record.class.primary_key} <> ?" condition_params << record.send(:id) end # Remove current account to prevent scopping account = Account.current_account Account.current_account = nil finder_class.with_exclusive_scope do if finder_class.exists?([condition_sql, *condition_params]) record.errors.add(attr_name, :taken, :default => configuration[:message], :value => value) end end # Restore current account Account.current_account = account end end |