lib/sequel/plugins/validation_helpers.rb in sequel-4.49.0 vs lib/sequel/plugins/validation_helpers.rb in sequel-5.0.0

- old
+ new

@@ -36,22 +36,29 @@ # :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 - # changing the values of the Sequel::Plugins::ValidationHelpers::DEFAULT_OPTIONS hash. You - # change change the default options on a per model basis - # by overriding a private instance method default_validation_helpers_options. - # + # 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: # - # Sequel::Plugins::ValidationHelpers::DEFAULT_OPTIONS.merge!( - # :exact_length=>{:message=>lambda{|exact| I18n.t("errors.exact_length", :exact => exact)}}, - # :integer=>{:message=>lambda{I18n.t("errors.integer")}} - # ) + # 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" @@ -59,24 +66,20 @@ # # 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 - # ATTRIBUTE_JOINER = I18n.t('errors.joiner').freeze # 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(ATTRIBUTE_JOINER)} #{e}")} + # errors.each {|e| m << (e.is_a?(LiteralString) ? e : "#{Array(att).join(I18n.t('errors.joiner'))} #{e}")} # m # end # end # end module ValidationHelpers - # Default validation options used by Sequel. Can be modified to change the error - # messages for all models (e.g. for internationalization), or to set certain - # default options for validations (e.g. :allow_nil=>true for all validates_format). 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"}}, @@ -87,13 +90,12 @@ :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'}} - } - DEFAULT__OPTIONS = DEFAULT_OPTIONS - Sequel::Deprecation.deprecate_constant(self, :DEFAULT_OPTIONS) + }.freeze + DEFAULT_OPTIONS.each_value(&:freeze) module InstanceMethods # Check that the attribute values are the given exact length. def validates_exact_length(exact, atts, opts=OPTS) validatable_attributes_for_type(:exact_length, atts, opts){|a,v,m| validation_error_message(m, exact) if v.nil? || v.length != exact} @@ -104,11 +106,11 @@ validatable_attributes_for_type(:format, atts, opts){|a,v,m| validation_error_message(m, with) unless v.to_s =~ with} end # Check attribute value(s) is included in the given set. def validates_includes(set, atts, opts=OPTS) - validatable_attributes_for_type(:includes, atts, opts){|a,v,m| validation_error_message(m, set) unless set.send(set.respond_to?(:cover?) ? :cover? : :include?, v)} + validatable_attributes_for_type(:includes, atts, opts){|a,v,m| validation_error_message(m, set) unless set.public_send(set.respond_to?(:cover?) ? :cover? : :include?, v)} end # Check attribute value(s) string representation is a valid integer. def validates_integer(atts, opts=OPTS) validatable_attributes_for_type(:integer, atts, opts) do |a,v,m| @@ -121,11 +123,11 @@ end end # Check that the attribute values length is in the specified range. def validates_length_range(range, atts, opts=OPTS) - validatable_attributes_for_type(:length_range, atts, opts){|a,v,m| validation_error_message(m, range) if v.nil? || !range.send(range.respond_to?(:cover?) ? :cover? : :include?, v.length)} + validatable_attributes_for_type(:length_range, atts, opts){|a,v,m| validation_error_message(m, range) if v.nil? || !range.cover?(v.length)} end # Check that the attribute values are not longer than the given max length. # # Accepts a :nil_message option that is the error message to use when the @@ -163,11 +165,11 @@ end # Check attribute value(s) against a specified value and operation, e.g. # validates_operator(:>, 3, :value) validates that value > 3. def validates_operator(operator, rhs, atts, opts=OPTS) - validatable_attributes_for_type(:operator, atts, opts){|a,v,m| validation_error_message(m, operator, rhs) if v.nil? || !v.send(operator, rhs)} + validatable_attributes_for_type(:operator, atts, opts){|a,v,m| validation_error_message(m, operator, rhs) if v.nil? || !v.public_send(operator, rhs)} end # Validates for all of the model columns (or just the given columns) # that the column value is an instance of the expected class based on # the column's schema type. @@ -221,22 +223,22 @@ # 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. + # 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=>(proc do |ds, obj, cols| + # validates_unique :column, where:(lambda do |ds, obj, cols| # ds.where(cols.map do |c| - # v = obj.send(c) + # v = obj.public_send(c) # v = v.downcase if v # [Sequel.function(:lower, c), v] # end) # end) def validates_unique(*atts) @@ -248,12 +250,11 @@ from_values = opts[:from] == :values where = opts[:where] atts.each do |a| arr = Array(a) next if arr.any?{|x| errors.on(x)} - # SEQUEL5: Default only_if_modified to true - next if opts[:only_if_modified] && !new? && !arr.any?{|x| changed_columns.include?(x)} + next if opts.fetch(:only_if_modified, true) && !new? && !arr.any?{|x| changed_columns.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)} @@ -274,10 +275,10 @@ # The default options hash for the given type of validation. Can # be overridden on a per-model basis for different per model defaults. # The hash return must include a :message option that is either a # proc or string. def default_validation_helpers_options(type) - DEFAULT__OPTIONS[type] + DEFAULT_OPTIONS[type] end # Skip validating any attribute that matches one of the allow_* options. # Otherwise, yield the attribute, value, and passed option :message to # the block. If the block returns anything except nil or false, add it as