Class: Axn::FormObject

Inherits:
Object
  • Object
show all
Includes:
ActiveModel::Model
Defined in:
lib/axn/form_object.rb

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Class Attribute Details

.field_namesObject

Returns the value of attribute field_names.



14
15
16
# File 'lib/axn/form_object.rb', line 14

def field_names
  @field_names
end

Class Method Details

.attr_accessor(*attributes) ⇒ Object

Override attr_accessor to track field names for automatic #to_h support



24
25
26
27
28
29
30
31
32
# File 'lib/axn/form_object.rb', line 24

def attr_accessor(*attributes)
  # Initialize field_names if not already set
  self.field_names ||= []

  # Add new attributes to the field_names array
  self.field_names += attributes.map(&:to_sym)

  super
end

.inherited(subclass) ⇒ Object



16
17
18
19
20
21
# File 'lib/axn/form_object.rb', line 16

def inherited(subclass)
  # Inherit field_names from parent class, or initialize as empty array if parent doesn't have any
  subclass.field_names = (field_names || []).dup

  super
end

.nested_forms(**kwargs) ⇒ Object Also known as: nested_form

Add support for nested forms



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/axn/form_object.rb', line 46

def nested_forms(**kwargs)
  kwargs.each do |name, klass|
    validates name, presence: true

    define_method("#{name}=") do |params|
      return instance_variable_set("@#{name}", nil) if params.nil?

      child_params = params.dup

      # Automatically inject the parent into the child form if it has a parent= method
      child_params[:parent_form] = self if klass.instance_methods.include?(:parent_form=)

      instance_variable_set("@#{name}", klass.new(child_params))
    end

    validation_method_name = :"validate_#{name}_form"
    validate validation_method_name
    define_method(validation_method_name) do
      return if public_send(name).nil? || public_send(name).valid?

      public_send(name).errors.each do |error|
        errors.add("#{name}.#{error.attribute}", error.message)
      end
    end
    private validation_method_name
  end
end

.validates(*attributes) ⇒ Object

Automatically attr_accessor any attribute for which we add a validation



35
36
37
38
39
40
41
42
43
# File 'lib/axn/form_object.rb', line 35

def validates(*attributes)
  our_attributes = attributes.dup

  # Pulled from upstream: https://github.com/rails/rails/blob/6f0d1ad14b92b9f5906e44740fce8b4f1c7075dc/activemodel/lib/active_model/validations/validates.rb#L106
  our_attributes.extract_options!
  our_attributes.each { |attr| attr_accessor(attr) }

  super
end

Instance Method Details

#to_hObject



76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/axn/form_object.rb', line 76

def to_h
  return {} if self.class.field_names.nil?

  self.class.field_names.each_with_object({}) do |field_name, hash|
    next unless respond_to?(field_name)

    # Skip parent_form to avoid infinite recursion with circular references
    next if field_name == :parent_form

    value = public_send(field_name)
    hash[field_name] = value.is_a?(Axn::FormObject) ? value.to_h : value
  end
end