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 +7 -0
- data/lib/formwandler.rb +1 -0
- data/lib/formwandler/field.rb +97 -0
- data/lib/formwandler/field_definition.rb +26 -0
- data/lib/formwandler/form.rb +137 -0
- metadata +62 -0
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
|
data/lib/formwandler.rb
ADDED
@@ -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: []
|