formwandler 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1819221ed8cfcaee304d259ef15aa55aaf708048
4
+ data.tar.gz: 797085a3cd7806da1f9440b9a6d145648bdf840c
5
+ SHA512:
6
+ metadata.gz: 0f51d5d47fc62c67637c824993fde8045e763f652ca0394eadd8b93292c1073d7bca93661e39cb2ce0818bbc8c4c226e45012a46687c103ad337b1b3b136ac27
7
+ data.tar.gz: d79738347d59093d801c57e56a69db4784a6cac20e0af155f2e91be8f796bc1ff1c58bfdddc8924b112d4093f9239e09d0acb705c604887c05bbd1fe01a5ab2a
@@ -0,0 +1 @@
1
+ require_relative 'formwandler/form'
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formwandler
4
+ class Field
5
+ attr_reader :form, :field_definition
6
+
7
+ delegate :name, :model, :source, to: :field_definition
8
+
9
+ def initialize(form:, field_definition:)
10
+ @form = form
11
+ @field_definition = field_definition
12
+ end
13
+
14
+ def hidden?
15
+ if field_definition.hidden.respond_to?(:call)
16
+ form.instance_exec(&field_definition.hidden)
17
+ else
18
+ field_definition.hidden
19
+ end
20
+ end
21
+
22
+ def visible?
23
+ !hidden?
24
+ end
25
+
26
+ def disabled?
27
+ if field_definition.disabled.respond_to?(:call)
28
+ form.instance_exec(&field_definition.disabled)
29
+ else
30
+ field_definition.disabled
31
+ end
32
+ end
33
+
34
+ def options
35
+ all_options - hidden_options
36
+ end
37
+
38
+ def default?
39
+ !field_definition.default.nil?
40
+ end
41
+
42
+ def default
43
+ if field_definition.default.respond_to?(:call)
44
+ form.instance_exec(&field_definition.default)
45
+ else
46
+ field_definition.default
47
+ end
48
+ end
49
+
50
+ def delocalize
51
+ if field_definition.delocalize.respond_to?(:call)
52
+ form.instance_exec(&field_definition.delocalize)
53
+ else
54
+ field_definition.delocalize
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def all_options
61
+ _evaluate_field_definition_value(:options) || options_from_model || []
62
+ end
63
+
64
+ def hidden_options
65
+ field_definition.hidden_options&.reject do |_option, value|
66
+ _evaluate_value(value)
67
+ end&.keys || []
68
+ end
69
+
70
+ def options_from_model
71
+ return unless model_instance.present? && model_instance.is_a?(ActiveRecord::Base)
72
+ return unless enum_field?
73
+ model_instance.class.public_send(name.to_s.pluralize).keys
74
+ end
75
+
76
+ def enum_field?
77
+ model_instance.class.attribute_types[name.to_s].is_a?(ActiveRecord::Enum::EnumType)
78
+ end
79
+
80
+ def model_instance
81
+ form.models[field_definition.model]
82
+ end
83
+
84
+ def _evaluate_field_definition_value(attr_name)
85
+ value = field_definition.send(attr_name)
86
+ _evaluate_value(value)
87
+ end
88
+
89
+ def _evaluate_value(value)
90
+ if value.respond_to?(:call)
91
+ form.instance_exec(&value)
92
+ else
93
+ value
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Formwandler
4
+ class FieldDefinition
5
+ attr_reader :name, :hidden, :disabled, :default, :delocalize, :model, :source, :options
6
+
7
+ def initialize(name, hidden: false, disabled: false, default: nil, delocalize: nil, model: nil, source: nil, options: nil)
8
+ @name = name
9
+ @hidden = hidden
10
+ @disabled = disabled
11
+ @default = default
12
+ @delocalize = delocalize
13
+ @model = model
14
+ @source = source || name
15
+ @options = options
16
+ end
17
+
18
+ def hide_option(name, value = true)
19
+ hidden_options[name.to_sym] = value
20
+ end
21
+
22
+ def hidden_options
23
+ @hidden_options ||= {}
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'field_definition'
4
+ require_relative 'field'
5
+
6
+ module Formwandler
7
+ class Form
8
+ include ActiveModel::Model
9
+ include ActiveModel::Validations::Callbacks
10
+
11
+ class << self
12
+ def model_name
13
+ ActiveModel::Name.new(self, nil, name.chomp('Form').underscore)
14
+ end
15
+
16
+ def field_definitions
17
+ @field_definitions ||= {}
18
+ end
19
+
20
+ def field(name, opts = {})
21
+ field_definitions[name] = FieldDefinition.new(name, opts)
22
+
23
+ yield(field_definitions[name]) if block_given?
24
+
25
+ if field_definitions[name].model.present?
26
+ attribute_accessor(name, field_definitions[name])
27
+ else
28
+ attr_accessor name
29
+ end
30
+ end
31
+
32
+ def attribute_accessor(name, field_definition)
33
+ define_method "#{name}=" do |value|
34
+ models[field_definition.model].send("#{field_definition.source}=", value)
35
+ end
36
+
37
+ define_method name do
38
+ models[field_definition.model].send(field_definition.source)
39
+ end
40
+ end
41
+
42
+ def save_order(*model_names)
43
+ @model_save_order = model_names
44
+ end
45
+
46
+ attr_reader :model_save_order
47
+ end
48
+
49
+ attr_reader :fields, :models, :current_user
50
+
51
+ def initialize(models: {}, current_user: nil)
52
+ @models = models.symbolize_keys
53
+ @current_user = current_user
54
+
55
+ initialize_fields
56
+ initialize_models
57
+ assign_defaults
58
+ end
59
+
60
+ def persisted?
61
+ models.values.first&.persisted? || false
62
+ end
63
+
64
+ def to_param
65
+ models.values.first.to_param
66
+ end
67
+
68
+ def field(name)
69
+ fields.fetch(name)
70
+ end
71
+
72
+ def fields_for_model(model)
73
+ fields.values.select { |field| field.model == model }
74
+ end
75
+
76
+ def models_valid?
77
+ all_valid = true
78
+ models.each do |name, model|
79
+ all_valid = false if model.invalid?
80
+ fields_for_model(name).each do |field|
81
+ model.errors[field.source].each do |error_message|
82
+ errors.add(field.name, error_message)
83
+ end
84
+ end
85
+ end
86
+ all_valid
87
+ end
88
+
89
+ def submit(params)
90
+ assign_attributes permitted_params(params)
91
+
92
+ if valid? && models_valid?
93
+ save_models!
94
+ load_results
95
+ else
96
+ false
97
+ end
98
+ end
99
+
100
+ protected
101
+
102
+ def initialize_models
103
+ end
104
+
105
+ def assign_defaults
106
+ fields.values.each do |field|
107
+ next unless field.default?
108
+ send("#{field.name}=", field.default) if send(field.name).nil?
109
+ end
110
+ end
111
+
112
+ def save_models!
113
+ models.sort_by do |(name, _model)|
114
+ self.class.model_save_order.index(name) || self.class.model_save_order.size
115
+ end.map(&:last).compact.each(&:save!)
116
+ end
117
+
118
+ def load_results
119
+ true
120
+ end
121
+
122
+ def permitted_params(params)
123
+ visible_fields = fields.values.reject(&:hidden?).map(&:name)
124
+ delocalizations = fields.transform_values(&:delocalize).compact
125
+ params = ActionController::Parameters.new(params) if params.is_a?(Hash)
126
+ params.require(model_name.param_key).permit(*visible_fields).delocalize(delocalizations)
127
+ end
128
+
129
+ private
130
+
131
+ def initialize_fields
132
+ @fields = self.class.field_definitions.transform_values do |field_definition|
133
+ Field.new(form: self, field_definition: field_definition)
134
+ end
135
+ end
136
+ end
137
+ end
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: formwandler
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Stefan Bilharz
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-09-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5.0'
27
+ description: Create form objects for multiple models, dynamically mark fields as hidden
28
+ or disabled and even hide select options dynamically
29
+ email: sbilharz@heilmannsoftware.de
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - lib/formwandler.rb
35
+ - lib/formwandler/field.rb
36
+ - lib/formwandler/field_definition.rb
37
+ - lib/formwandler/form.rb
38
+ homepage:
39
+ licenses:
40
+ - MIT
41
+ metadata: {}
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: '2.3'
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements: []
57
+ rubyforge_project:
58
+ rubygems_version: 2.6.13
59
+ signing_key:
60
+ specification_version: 4
61
+ summary: Form objects for rails
62
+ test_files: []