Method: Sequel::Plugins::ValidationHelpers::InstanceMethods#validates_unique
- Defined in:
- lib/sequel/plugins/validation_helpers.rb
permalink #validates_unique(*atts) ⇒ Object
Checks that there are no duplicate values in the database for the given attributes. Pass an array of fields instead of multiple fields to specify that the combination of fields must be unique, instead of that each field should have a unique value.
This means that the code:
validates_unique([:column1, :column2])
validates the grouping of column1 and column2 while
validates_unique(:column1, :column2)
validates them separately.
You can pass a block, which is yielded the dataset in which the columns must be unique. So if you are doing a soft delete of records, in which the name must be unique, but only for active records:
validates_unique(:name){|ds| ds.where(:active)}
You should also add a unique index in the database, as this suffers from a fairly obvious race condition.
This validation does not respect the :allow_* options that the other validations accept, since it can deal with a grouping of multiple attributes.
Possible Options:
- :dataset
-
The base dataset to use for the unique query, defaults to the model’s dataset.
- :message
-
The message to use (default: ‘is already taken’)
- :only_if_modified
-
Only check the uniqueness if the object is new or one of the columns has been modified, true by default.
- :where
-
A callable object where call takes three arguments, a dataset, the current object, and an array of columns, and should return a modified dataset that is filtered to include only rows with the same values as the current object for each column in the array.
If you want to do a case insensitive uniqueness validation on a database that is case sensitive by default, you can use:
validates_unique :column, where:(lambda do |ds, obj, cols|
ds.where(cols.map do |c|
v = obj.public_send(c)
v = v.downcase if v
[Sequel.function(:lower, c), v]
end)
end)
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
# File 'lib/sequel/plugins/validation_helpers.rb', line 272 def validates_unique(*atts) opts = (:unique) if atts.last.is_a?(Hash) opts = opts.merge(atts.pop) end = (opts[:message]) from_values = opts[:from] == :values where = opts[:where] atts.each do |a| arr = Array(a) next if arr.any?{|x| errors.on(x)} cc = changed_columns next if opts.fetch(:only_if_modified, true) && !new? && !arr.any?{|x| cc.include?(x)} ds = opts[:dataset] || model.dataset ds = if where where.call(ds, self, arr) else vals = arr.map{|x| from_values ? values[x] : get_column_value(x)} next if vals.any?(&:nil?) ds.where(arr.zip(vals)) end ds = yield(ds) if defined?(yield) unless new? h = ds.joined_dataset? ? qualified_pk_hash : pk_hash ds = ds.exclude(h) end errors.add(a, ) unless ds.empty? end end |