Class: Kadmin::Form

Inherits:
Object
  • Object
show all
Extended by:
ActiveModel::Translation
Includes:
ActiveModel::Validations
Defined in:
lib/kadmin/form.rb

Overview

Parsing is done by using attribute setters. If you have an attribute called name, then add a reader/writer for it, name and name=, and perform the parsing in name=. If there is no parsing to be done, you can simply delegate the method to the underlying model.

If the attribute is a nested form, in the writer, simply instantiate that form, and pass the attributes on to it, then update the model's association (if any) to reflect the changes.

Validation is performed like on a normal model or ActiveRecord object. If you have no extra validation to perform than that of the model, simply delegate the validate and valid? methods to the model.

To use nested forms, you need to add a reader and a writer. For example, for a form called Person, with potentially X nested Person forms as children, you would have:

Examples:

class PersonForm < Form
  def children
    [@child1, @child2]
  end

  def children_attributes=(attributes)
    ...instantiate subforms and pass attributes...
  end
end

Instance Attribute Summary collapse

Parsing/Deserialization collapse

Validation collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(model) ⇒ Form

Returns a new instance of Form.



41
42
43
44
45
# File 'lib/kadmin/form.rb', line 41

def initialize(model)
  @errors = ActiveModel::Errors.new(self)
  @model = model
  @form_input = {}
end

Instance Attribute Details

#model ⇒ ActiveModel::Model (readonly)

Returns underlying model to populate.

Returns:

  • (ActiveModel::Model) —

    underlying model to populate



37
38
39
# File 'lib/kadmin/form.rb', line 37

def model
  @model
end

Class Method Details

.delegate_attributes(*attributes) ⇒ Object

Delegates the list of attributes to the model, both readers and writers. If the attribute value passed is a hash and not a symbol, assumes it is a hash of one key, whose value is an array contained :reader, :writer, or both.

Examples:

delegate_attributes :first_name, { last_name: [:reader] }

Parameters:

  • attributes (Array<Symbol, Hash<Symbol, Array<Symbol>>>) —

    list of attributes to delegate to the model



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/kadmin/form.rb', line 100

def delegate_attributes(*attributes)
  delegates = attributes.reduce([]) do |acc, attribute|
    case attribute
    when Hash
      key, value = attribute.first
      acc << key if value.include?(:reader)
      acc << "#{key}=" if value.include?(:writer)
    when Symbol, String
      acc << attribute
    else
      raise(ArgumentError, 'Attribute must be one of: Hash, Symbol, String')
    end

    delegate(*delegates, to: model)
  end
end

Instance Method Details

#assign_attributes(form_input) ⇒ Object

Populates the model based on the form input. The input is typically obtained from the controller's params method, but can be any hash which conforms to whatever the form object is expecting. If some input was previously parsed, there is no "rollback" on the state of the model; it should be done prior to reparsing if it is necessary.

Parameters:

  • form_input (Hash<String, Object>) —

    a hash representing the raw form input



55
56
57
58
59
60
61
# File 'lib/kadmin/form.rb', line 55

def assign_attributes(form_input)
  @errors.clear
  form_input.each do |attr, value|
    setter = "#{attr}="
    send(setter, value) if respond_to?(setter)
  end
end

#model_valid? ⇒ Boolean

Validates the models and merge errors back into our own errors if they are invalid. Overload if you need to validate associations.

Examples:

class PersonForm < Form
  def model_valid?
    super
    if @model&.child&.changed? && !@model.child.valid?
      @errors.add(:base, :invalid, message: 'child model is invalid')
    end
  end
end

Returns:

  • (Boolean)


81
82
83
84
85
86
87
# File 'lib/kadmin/form.rb', line 81

def model_valid?
  unless @model.valid?
    @model.errors.each do |attribute, error|
      @errors.add(attribute, error)
    end
  end
end