module Sequel::Plugins::ValidationHelpers

  1. lib/sequel/plugins/validation_helpers.rb

The validation_helpers plugin contains validate_* methods designed to be called inside Model#validate to perform validations:

Sequel::Model.plugin :validation_helpers
class Album < Sequel::Model
  def validate
    super
    validates_min_length 1, :num_tracks
  end
end

The validates_unique method has a unique API, but the other validations have the API explained here:

Arguments:

atts

Single attribute symbol or an array of attribute symbols specifying the attribute(s) to validate.

Options:

:allow_blank

Whether to skip the validation if the value is blank.

:allow_missing

Whether to skip the validation if the attribute isn't a key in the values hash. This is different from allow_nil, because Sequel only sends the attributes in the values when doing an insert or update. If the attribute is not present, Sequel doesn't specify it, so the database will use the table's default value. This is different from having an attribute in values with a value of nil, which Sequel will send as NULL. If your database table has a non NULL default, this may be a good option to use. You don't want to use allow_nil, because if the attribute is in values but has a value nil, Sequel will attempt to insert a NULL value into the database, instead of using the database's default.

:allow_nil

Whether to skip the validation if the value is nil.

:from

Set to :values to pull column values from the values hash instead of calling the related method. Allows for setting up methods on the underlying column values, in the cases where the model transforms the underlying value before returning it, such as when using serialization.

:message

The message to use. Can be a string which is used directly, or a proc which is called. If the validation method takes a argument before the array of attributes, that argument is passed as an argument to the proc.

The default validation options for all models can be modified by overridding the Model#default_validation_helpers_options private method. By changing the default options, you can setup internationalization of the error messages. For example, you would modify the default options:

class Sequel::Model
  private

  def default_validation_helpers_options(type)
    case type
    when :exact_length
      {message: lambda{|exact| I18n.t("errors.exact_length", exact: exact)}}
    when :integer
      {message: lambda{I18n.t("errors.integer")}}
    else
      super
    end
  end
end

and then use something like this in your yaml translation file:

en:
  errors:
    exact_length: "is not %{exact} characters"
    integer: "is not a number"

Note that if you want to support internationalization of Errors#full_messages, you need to override the method. Here's an example:

class Sequel::Model::Errors
  def full_messages
    inject([]) do |m, kv|
      att, errors = *kv
      att.is_a?(Array) ? Array(att).map!{|v| I18n.t("attributes.#{v}")} : att = I18n.t("attributes.#{att}")
      errors.each {|e| m << (e.is_a?(LiteralString) ? e : "#{Array(att).join(I18n.t('errors.joiner'))} #{e}")}
      m
    end
  end
end

Constants

DEFAULT_OPTIONS = { :exact_length=>{:message=>lambda{|exact| "is not #{exact} characters"}}, :format=>{:message=>lambda{|with| 'is invalid'}}, :includes=>{:message=>lambda{|set| "is not in range or set: #{set.inspect}"}}, :integer=>{:message=>lambda{"is not a number"}}, :length_range=>{:message=>lambda{|range| "is too short or too long"}}, :max_length=>{:message=>lambda{|max| "is longer than #{max} characters"}, :nil_message=>lambda{"is not present"}}, :min_length=>{:message=>lambda{|min| "is shorter than #{min} characters"}}, :not_null=>{:message=>lambda{"is not present"}}, :numeric=>{:message=>lambda{"is not a number"}}, :operator=>{:message=>lambda{|operator, rhs| "is not #{operator} #{rhs}"}}, :type=>{:message=>lambda{|klass| klass.is_a?(Array) ? "is not a valid #{klass.join(" or ").downcase}" : "is not a valid #{klass.to_s.downcase}"}}, :presence=>{:message=>lambda{"is not present"}}, :unique=>{:message=>lambda{'is already taken'}} }.freeze