Sha256: eeb21f9f3fc6c49565e067ab449bed403c66f2c0a5472eff8c5d931f73eead06

Contents?: true

Size: 1.99 KB

Versions: 2

Compression:

Stored size: 1.99 KB

Contents

class MeasuredValidator < ActiveModel::EachValidator
  CHECKS = {
    greater_than: :>,
    greater_than_or_equal_to: :>=,
    equal_to: :==,
    less_than: :<,
    less_than_or_equal_to: :<=,
  }.freeze

  def validate_each(record, attribute, measurable)
    measured_config = record.class.measured_fields[attribute]
    unit_field_name = measured_config[:unit_field_name] || "#{ attribute }_unit"
    value_field_name = "#{ attribute }_value"

    measured_class = measured_config[:class]

    measurable_unit_name = record.public_send(unit_field_name)
    measurable_value = record.public_send(value_field_name)

    return unless measurable_unit_name.present? || measurable_value.present?

    measurable_unit = measured_class.unit_system.unit_for(measurable_unit_name)
    record.errors.add(attribute, message("is not a valid unit")) unless measurable_unit

    if options[:units]
      valid_units = Array(options[:units]).map { |unit| measured_class.unit_system.unit_for(unit) }
      record.errors.add(attribute, message("is not a valid unit")) unless valid_units.include?(measurable_unit)
    end

    if measurable_unit && measurable_value.present?
      options.slice(*CHECKS.keys).each do |option, value|
        comparable_value = value_for(value, record)
        comparable_value = measured_class.new(comparable_value, measurable_unit) unless comparable_value.is_a?(Measured::Measurable)
        unless measurable.public_send(CHECKS[option], comparable_value)
          record.errors.add(attribute, message("#{measurable.to_s} must be #{CHECKS[option]} #{comparable_value}"))
        end
      end
    end
  end

  private

  def message(default_message)
    options[:message] || default_message
  end

  def value_for(key, record)
    value = case key
    when Proc
      key.call(record)
    when Symbol
      record.send(key)
    else
      key
    end

    raise ArgumentError, ":#{ value } must be a number or a Measurable object" unless (value.is_a?(Numeric) || value.is_a?(Measured::Measurable))
    value
  end
end

Version data entries

2 entries across 2 versions & 1 rubygems

Version Path
measured-rails-2.0.0 lib/measured/rails/validations.rb
measured-rails-2.0.0.pre4 lib/measured/rails/validations.rb