Class: Readymade::Form
- Inherits:
-
Object
- Object
- Readymade::Form
- Includes:
- ActiveModel::Model
- Defined in:
- lib/readymade/form.rb
Direct Known Subclasses
Defined Under Namespace
Classes: FormOptions
Constant Summary collapse
- PERMITTED_ATTRIBUTES =
[].freeze
- REQUIRED_ATTRIBUTES =
[].freeze
Instance Attribute Summary collapse
-
#args ⇒ Object
Returns the value of attribute args.
-
#nested_forms ⇒ Object
readonly
list nested_forms in child form in order to validate them.
-
#params ⇒ Object
Returns the value of attribute params.
-
#record ⇒ Object
Returns the value of attribute record.
Instance Method Summary collapse
- #build_nested_forms ⇒ Object
-
#datetime_params ⇒ Object
list datetime_params in child form in order to parse datetime properly.
- #humanized_name ⇒ Object
-
#initialize(params, **args) ⇒ Form
constructor
A new instance of Form.
-
#nested_forms_mapping ⇒ Object
define nested forms in format { attr_name: MyFormClass } use the following syntax if attribute is a collection: { attr_collection_name: [MyFormClass] }.
-
#parse_datetime_params ⇒ Object
uses datetime_params to fix the following issue: stackoverflow.com/questions/5073756/where-is-the-rails-method-that-converts-data-from-datetime-select-into-a-datet.
- #permitted_attributes ⇒ Object
- #required_attributes ⇒ Object
-
#sync_errors(from: self, to: record) ⇒ Object
sync errors from form to record or vice-versa.
-
#sync_nested_errors(nested_forms) ⇒ Object
copy errors from nested forms into parent form.
- #validate ⇒ Object
- #validate_nested(*nested_forms) ⇒ Object
Constructor Details
#initialize(params, **args) ⇒ Form
Returns a new instance of Form.
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/readymade/form.rb', line 14 def initialize(params, **args) @params = params @record = args[:record] @args = args @nested_forms = [] @required_attributes = Array(args[:required]).presence @permitted_attributes = (Array(@required_attributes) + Array(args[:permitted])).presence parse_datetime_params # Slice all attributes which is not required by form # to omit save of unpredictable params @params&.slice!(*permitted_attributes) # if permitted_attributes.present? # dynamically creates attr accessors @permitted_attributes&.each do |key| singleton_class.class_eval do attr_accessor key end end # automatically validates all REQUIRED_ATTRIBUTES singleton_class.validates(*required_attributes, presence: true) if required_attributes.present? build_nested_forms super(@params) end |
Instance Attribute Details
#args ⇒ Object
Returns the value of attribute args.
9 10 11 |
# File 'lib/readymade/form.rb', line 9 def args @args end |
#nested_forms ⇒ Object (readonly)
list nested_forms in child form in order to validate them
150 151 152 |
# File 'lib/readymade/form.rb', line 150 def nested_forms @nested_forms end |
#params ⇒ Object
Returns the value of attribute params.
9 10 11 |
# File 'lib/readymade/form.rb', line 9 def params @params end |
#record ⇒ Object
Returns the value of attribute record.
9 10 11 |
# File 'lib/readymade/form.rb', line 9 def record @record end |
Instance Method Details
#build_nested_forms ⇒ Object
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/readymade/form.rb', line 53 def build_nested_forms nested_forms_mapping.each do |attr, form_class| next if params[attr].blank? if form_class.is_a?(Array) n_forms = if params[attr].is_a?(Hash) # { 0 => {id: 1, name: 'my name'}, 1 => { id: 2, name: 'other name' }} params[attr].map { |_i, attrs| form_class[0].new(attrs) } else # [{id: 1, name: 'my name'}, { id: 2, name: 'other name' }] params[attr].map { |attrs| form_class[0].new(attrs) } end @nested_forms.push(*n_forms) define_singleton_method("#{attr}_forms") { n_forms } else @nested_forms.push(f = form_class.new(params[attr])) define_singleton_method("#{attr}_form") { f } end end end |
#datetime_params ⇒ Object
list datetime_params in child form in order to parse datetime properly
145 146 147 |
# File 'lib/readymade/form.rb', line 145 def datetime_params [] end |
#humanized_name ⇒ Object
121 122 123 |
# File 'lib/readymade/form.rb', line 121 def humanized_name self.class.name.underscore.split('/')[0] end |
#nested_forms_mapping ⇒ Object
define nested forms in format { attr_name: MyFormClass } use the following syntax if attribute is a collection: { attr_collection_name: [MyFormClass] }
154 155 156 |
# File 'lib/readymade/form.rb', line 154 def nested_forms_mapping {} end |
#parse_datetime_params ⇒ Object
uses datetime_params to fix the following issue: stackoverflow.com/questions/5073756/where-is-the-rails-method-that-converts-data-from-datetime-select-into-a-datet
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/readymade/form.rb', line 127 def parse_datetime_params datetime_params.each do |param| next if @params[param].present? # set datetime to nil if year is blank if @params["#{param}(1i)"].blank? @params[param] = nil next end @params[param] = DateTime.new(*(1..5).map { |i| @params["#{param}(#{i}i)"].to_i }) end rescue ArgumentError nil end |
#permitted_attributes ⇒ Object
43 44 45 |
# File 'lib/readymade/form.rb', line 43 def permitted_attributes @permitted_attributes ||= self.class::PERMITTED_ATTRIBUTES end |
#required_attributes ⇒ Object
47 48 49 50 51 |
# File 'lib/readymade/form.rb', line 47 def required_attributes return [] if params.try(:[], :_destroy).present? @required_attributes ||= self.class::REQUIRED_ATTRIBUTES end |
#sync_errors(from: self, to: record) ⇒ Object
sync errors from form to record or vice-versa
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/readymade/form.rb', line 102 def sync_errors(from: self, to: record) return if [from, to].any?(&:blank?) if rails_errors_v2? from.errors..each do |key, values| Array.wrap(values).uniq.each do |uv| to.errors.add(key, uv) end end else errors = from.errors.instance_variable_get('@messages').to_h errors.merge!(to.errors.instance_variable_get('@messages').to_h) to.errors.instance_variable_set('@messages', errors) to.errors..transform_values!(&:uniq) # Does not work with rails 6.1 end rescue FrozenError => _e end |
#sync_nested_errors(nested_forms) ⇒ Object
copy errors from nested forms into parent form
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/readymade/form.rb', line 83 def sync_nested_errors(nested_forms) if rails_errors_v2? nested_forms.each do |n_form| n_form.errors.each do |code| errors.add("#{n_form.humanized_name}.#{code.attribute}", code.) end end else nested_forms.each do |n_form| n_form.errors.each do |code, text| errors.add("#{n_form.humanized_name}.#{code}", text) end end end false end |
#validate ⇒ Object
74 75 76 |
# File 'lib/readymade/form.rb', line 74 def validate super && validate_nested(*nested_forms) end |
#validate_nested(*nested_forms) ⇒ Object
78 79 80 |
# File 'lib/readymade/form.rb', line 78 def validate_nested(*nested_forms) nested_forms.compact.map(&:validate).all? || sync_nested_errors(nested_forms) end |