Class: Forms::Validations::Introspector

Inherits:
Object
  • Object
show all
Defined in:
lib/forms/validations/introspector.rb

Overview

Introspects an ActiveModel class (or instance) and translates each attribute's validators into a data: hash ready to merge into a Phlex element. Phlex handles the data- prefixing and underscore-to-hyphen conversion at render time.

Sticks to validators whose semantics are reproducible client side. Skips anything with :if / :unless / :on because those need server context the browser doesn't have. Server validation remains authoritative — the client side just shortens the loop for the common cases.

Defined Under Namespace

Classes: Null

Constant Summary collapse

CONTROLLER_PREFIX =
"forms--validations"
SUPPORTED =

Validators we know how to mirror. Keys are the short class name (without namespace), values are the controller suffix appended to CONTROLLER_PREFIX. Matching on the short name picks up both ActiveModel::Validations::* (form objects) and ActiveRecord::Validations::* (AR models inherit a parallel set of subclasses for uniqueness/etc.) without listing both namespaces.

{
  "PresenceValidator" => "presence",
  "LengthValidator" => "length",
  "FormatValidator" => "format",
  "NumericalityValidator" => "numericality",
  "InclusionValidator" => "inclusion",
  "ExclusionValidator" => "exclusion",
  "ConfirmationValidator" => "confirmation",
  "AcceptanceValidator" => "acceptance"
}.freeze
LENGTH_KEYS =
%i[maximum minimum is].freeze
NUMERICALITY_KEYS =
%i[
  greater_than greater_than_or_equal_to
  less_than less_than_or_equal_to
  equal_to other_than
  only_integer odd even
].freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(model_class) ⇒ Introspector

Returns a new instance of Introspector.



56
57
58
# File 'lib/forms/validations/introspector.rb', line 56

def initialize(model_class)
  @model_class = model_class
end

Class Method Details

.for(model_or_class) ⇒ Object

Convenience: returns a null introspector for nil models so callers don't need to guard.



47
48
49
50
51
52
53
54
# File 'lib/forms/validations/introspector.rb', line 47

def self.for(model_or_class)
  return Null.new if model_or_class.nil?

  klass = model_or_class.is_a?(Class) ? model_or_class : model_or_class.class
  return Null.new unless klass.respond_to?(:validators_on)

  new(klass)
end

Instance Method Details

#data_attributes_for(attribute) ⇒ Object

Returns a hash of the shape:

{
controller: "forms--validations--presence forms--validations--length",
forms__validations__presence_required_value: "true",
forms__validations__length_maximum_value: "60",
}

Returns {} when no supported validators are present. The double-underscore key encoding survives Phlex/Rails' underscore-to-hyphen rewrite: __- (deliberate).



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/forms/validations/introspector.rb', line 70

def data_attributes_for(attribute)
  validators = applicable_validators(attribute)
  return {} if validators.empty?

  controllers = []
  attrs = {}

  validators.each do |validator|
    suffix = SUPPORTED[validator.class.name.split("::").last]
    next unless suffix

    controllers << "#{CONTROLLER_PREFIX}--#{suffix}"
    value_attributes(suffix, validator, attribute).each do |key, value|
      attrs[data_key(suffix, key)] = value
    end
  end

  return {} if controllers.empty?

  { controller: controllers.uniq.join(" ") }.merge(attrs)
end