Class: OnForm::Form

Inherits:
Object
  • Object
show all
Includes:
ActiveModel::Validations, ActiveModel::Validations::Callbacks, Attributes, Errors, MultiparameterAttributes, Saving, Validations
Defined in:
lib/on_form/form.rb

Class Method Summary collapse

Methods included from Saving

included, #save, #save!, #transaction, #update, #update!

Methods included from Errors

#errors, #reset_errors

Methods included from MultiparameterAttributes

#assign_multiparameter_attributes, #execute_callstack_for_multiparameter_attributes, #extract_callstack_for_multiparameter_attributes, #find_parameter_position, #type_cast_attribute_value

Methods included from Attributes

#[], #[]=, #attribute_names, #attributes, #attributes=, #read_attribute_for_validation, #write_attribute

Methods included from Validations

#form_errors?, included, #invalid?

Class Method Details

.attribute(name, type, options = {}) ⇒ Object



62
63
64
65
66
67
68
69
70
# File 'lib/on_form/form.rb', line 62

def self.attribute(name, type, options = {})
  name = name.to_sym
  introduced_attribute_types[name] = Types.lookup(type, options)
  define_method(name)                       { introduced_attribute_values.fetch(name) { type = self.class.introduced_attribute_types[name]; type.cast(introduced_attribute_values_before_type_cast.fetch(name) { type.default }) } }
  define_method("#{name}_before_type_cast") { introduced_attribute_values_before_type_cast[name] }
  define_method("#{name}_changed?")         { send(name) != send("#{name}_was") }
  define_method("#{name}_was")              { type = self.class.introduced_attribute_types[name]; type.cast(type.default) }
  define_method("#{name}=")                 { |arg| introduced_attribute_values.delete(name); introduced_attribute_values_before_type_cast[name] = arg }
end

.expose(backing_attribute_names, on: nil, prefix: nil, suffix: nil, as: nil) ⇒ Object

Raises:

  • (ArgumentError)


31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/on_form/form.rb', line 31

def self.expose(backing_attribute_names, on: nil, prefix: nil, suffix: nil, as: nil)
  backing_attribute_names = Array(backing_attribute_names)
  raise ArgumentError, "can't expose multiple attributes as the same form attribute!" if as && backing_attribute_names.size != 1

  raise ArgumentError, "must choose the model to expose the attributes on" unless on || identity_model_name
  on = (on || identity_model_name).to_sym
  expose_backing_model(on)

  backing_attribute_names.each do |backing_name|
    exposed_name = as || "#{prefix}#{backing_name}#{suffix}"
    expose_attribute(on, exposed_name, backing_name)
  end
end

.expose_attribute(backing_model_name, exposed_name, backing_name) ⇒ Object



51
52
53
54
55
56
57
58
59
60
# File 'lib/on_form/form.rb', line 51

def self.expose_attribute(backing_model_name, exposed_name, backing_name)
  exposed_attributes[backing_model_name][exposed_name.to_sym] = backing_name.to_sym

  define_method(exposed_name)                       { backing_model_instance(backing_model_name).send(backing_name) }
  define_method("#{exposed_name}_before_type_cast") { backing_model_instance(backing_model_name).send("#{backing_name}_before_type_cast") }
  define_method("#{exposed_name}?")                 { backing_model_instance(backing_model_name).send("#{backing_name}?") }
  define_method("#{exposed_name}_changed?")         { backing_model_instance(backing_model_name).send("#{backing_name}_changed?") }
  define_method("#{exposed_name}_was")              { backing_model_instance(backing_model_name).send("#{backing_name}_was") }
  define_method("#{exposed_name}=")                 { |arg| backing_model_instance(backing_model_name).send("#{backing_name}=", arg) }
end

.expose_backing_model(backing_model_name) ⇒ Object



45
46
47
48
49
# File 'lib/on_form/form.rb', line 45

def self.expose_backing_model(backing_model_name)
  unless instance_methods.include?(backing_model_name)
    attr_reader backing_model_name
  end
end

.expose_collection_of(association_name, on: nil, prefix: nil, suffix: nil, as: nil, allow_insert: true, allow_update: true, allow_destroy: false, reject_if: nil, &block) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/on_form/form.rb', line 79

def self.expose_collection_of(association_name, on: nil, prefix: nil, suffix: nil, as: nil,
                              allow_insert: true, allow_update: true, allow_destroy: false, reject_if: nil, &block)

  exposed_name = as || "#{prefix}#{association_name}#{suffix}"
  singular_name = exposed_name.to_s.singularize
  association_name = association_name.to_sym

  on = prepare_model_to_expose!(on)

  collection_form_class = Class.new(OnForm::Form)
  const_set(exposed_name.to_s.classify + "Form", collection_form_class)

  collection_form_class.send(:define_method, :initialize) { |record| @record = record }
  collection_form_class.send(:attr_reader, :record)
  collection_form_class.send(:alias_method, singular_name, :record)
  collection_form_class.take_identity_from singular_name, convert_to_model: false
  collection_form_class.class_eval(&block)

  # used by action_view's fields_for, and by the following lines
  define_method(exposed_name) do
    collection_wrappers[association_name] ||= CollectionWrapper.new(
      backing_model_instance(on), association_name, collection_form_class,
      allow_insert: allow_insert, allow_update: allow_update,
      allow_destroy: allow_destroy, reject_if: reject_if
    )
  end
  define_method("#{exposed_name}_attributes=") { |params| send(exposed_name).parse_collection_attributes(params) }

  collection_form_class
end

.exposed_attributesObject



12
13
14
# File 'lib/on_form/form.rb', line 12

def self.exposed_attributes
  @exposed_attributes ||= Hash.new { |h, k| h[k] = {} }
end

.identity_model_nameObject



20
21
22
# File 'lib/on_form/form.rb', line 20

def self.identity_model_name
  @identity_model_name
end

.inherited(child) ⇒ Object



25
26
27
28
# File 'lib/on_form/form.rb', line 25

def inherited(child)
  exposed_attributes.each { |k, v| child.exposed_attributes[k].merge!(v) }
  child.introduced_attribute_types.merge!(introduced_attribute_types)
end

.introduced_attribute_typesObject



16
17
18
# File 'lib/on_form/form.rb', line 16

def self.introduced_attribute_types
  @introduced_attribute_types ||= {}
end

.take_identity_from(backing_model_name, convert_to_model: true) ⇒ Object



72
73
74
75
76
77
# File 'lib/on_form/form.rb', line 72

def self.take_identity_from(backing_model_name, convert_to_model: true)
  @identity_model_name = backing_model_name.to_sym
  expose_backing_model(@identity_model_name)
  delegate :id, :to_key, :to_param, :persisted?, :mark_for_destruction, :_destroy, :marked_for_destruction?, to: backing_model_name
  delegate :to_model, to: backing_model_name if convert_to_model
end