model_form_facade 0.2.0 → 0.3.0
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 +4 -4
- data/CHANGELOG.md +22 -0
- data/lib/model_form_facade/version.rb +1 -1
- data/lib/model_form_facade.rb +44 -5
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '06090477510745144a75c5edcf7d2dfe6c7941a9bc64d5b73b1a1269cfb6db70'
|
|
4
|
+
data.tar.gz: f0ea4453cb4cda4a9c1f4cb33aa787c2b457c3724f49d919859f82d453498253
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 619871d42f8eaa331dab60444c9288e936bdb762c874e1b5a77e9fa2cf1ae687f6740218ea1effd46a48821a4c97914d41bb187b47c5237596d1eff6c7274dab
|
|
7
|
+
data.tar.gz: d68357db0bd0271959eba026742b5b22f7ae18328ae28526a50c036bf259c48e634d9735818b82da16a0eb73e130b5c147a4f075706446bf2abba452f44be0b5
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.3.0] - 2026-05-20
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **Breaking:** Fields on forms backed by multi-word class names (e.g. `FooBar`) now generate correctly parameterized field names (`foo_bar[field]` instead of `foobar[field]`).
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Array fields now accept both a plain array and a numeric-keyed hash (Rails strong params style), making it easier to handle form submissions without manual coercion.
|
|
12
|
+
|
|
13
|
+
## [0.2.0] - 2025-08-30
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- Nested forms with custom `read:`, `write:`, and `attribute:` mappings now work correctly — nested object and array fields are routed through the inner form's write logic.
|
|
18
|
+
- `as_written(hash)` class method returns the attributes hash as they would be written to the backing object, without needing a real model instance.
|
|
19
|
+
- `#errors` now joins multiple validation messages with a readable separator.
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- `Field type: :array` write method no longer errors on assignment.
|
|
24
|
+
|
|
3
25
|
## [0.1.0] - 2025-08-27
|
|
4
26
|
|
|
5
27
|
- Initial release
|
data/lib/model_form_facade.rb
CHANGED
|
@@ -12,6 +12,7 @@ module ModelFormFacade
|
|
|
12
12
|
attr_reader :object
|
|
13
13
|
private attr_writer :object
|
|
14
14
|
private attr_accessor :component_props
|
|
15
|
+
delegate :model_name, :to_key, :to_model, to: :object
|
|
15
16
|
end
|
|
16
17
|
|
|
17
18
|
def initialize(model_object = nil, root: nil, **component_props)
|
|
@@ -42,7 +43,7 @@ module ModelFormFacade
|
|
|
42
43
|
errs = object_error_messages.reject { |k, v| k.to_s.include? "." } # Remove nested, we'll recurse
|
|
43
44
|
hash = self.class.fields.values.filter_map do |field|
|
|
44
45
|
err = case field.type
|
|
45
|
-
in :scalar then errs[field.attribute]&.map(&:capitalize)&.join(";").presence
|
|
46
|
+
in :scalar then errs[field.attribute]&.map(&:capitalize)&.join("; ").presence
|
|
46
47
|
in :object then field.form.new(send(field.name)).errors(root: false)
|
|
47
48
|
in :array then (send(field.name) || []).map { field.form.new(_1).errors(root: false) }
|
|
48
49
|
end
|
|
@@ -63,15 +64,16 @@ module ModelFormFacade
|
|
|
63
64
|
|
|
64
65
|
def set_fields(params, root: nil)
|
|
65
66
|
params = params.expect(expectation(root:)) if params.respond_to?(:expect) && !params.permitted?
|
|
66
|
-
|
|
67
|
+
assign_attributes(params)
|
|
67
68
|
end
|
|
68
69
|
alias_method :fields=, :set_fields
|
|
69
70
|
|
|
70
|
-
def
|
|
71
|
+
def assign_attributes(hash)
|
|
71
72
|
hash.each do |key, value|
|
|
72
73
|
send("#{key}=", value)
|
|
73
74
|
end
|
|
74
75
|
end
|
|
76
|
+
alias_method :attributes=, :assign_attributes
|
|
75
77
|
|
|
76
78
|
def attributes = as_json
|
|
77
79
|
|
|
@@ -85,7 +87,7 @@ module ModelFormFacade
|
|
|
85
87
|
|
|
86
88
|
private def _params_root(root: nil)
|
|
87
89
|
case root.nil? ? params_root : root
|
|
88
|
-
in true then
|
|
90
|
+
in true then model_name&.param_key&.to_sym
|
|
89
91
|
in false then nil
|
|
90
92
|
in Symbol => sym then sym
|
|
91
93
|
in String => str then str.to_sym
|
|
@@ -101,6 +103,21 @@ module ModelFormFacade
|
|
|
101
103
|
end
|
|
102
104
|
end
|
|
103
105
|
|
|
106
|
+
class MockObject
|
|
107
|
+
attr_accessor :attributes
|
|
108
|
+
|
|
109
|
+
def self.define_writer(write_method)
|
|
110
|
+
key = write_method.to_s.delete_suffix("=")
|
|
111
|
+
define_method(write_method) do |v|
|
|
112
|
+
attributes[key] = v
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def initialize
|
|
117
|
+
self.attributes = {}
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
104
121
|
module FieldMethods; end
|
|
105
122
|
|
|
106
123
|
class_methods do
|
|
@@ -124,6 +141,13 @@ module ModelFormFacade
|
|
|
124
141
|
{root => expected}
|
|
125
142
|
end
|
|
126
143
|
|
|
144
|
+
def as_written(hash)
|
|
145
|
+
obj = mock_object_class.new
|
|
146
|
+
instance = new(obj)
|
|
147
|
+
instance.assign_attributes(hash)
|
|
148
|
+
obj.attributes
|
|
149
|
+
end
|
|
150
|
+
|
|
127
151
|
private
|
|
128
152
|
|
|
129
153
|
def _relation(name, allow_destroy: false, form: nil, read: nil, write: nil, attribute: nil, type: nil, &block)
|
|
@@ -144,7 +168,18 @@ module ModelFormFacade
|
|
|
144
168
|
field = Field.new(name:, read:, write:, attribute:, type:, form:)
|
|
145
169
|
self.fields = {**fields, name.to_sym => field}
|
|
146
170
|
field_methods_module.define_method(name) { object&.send(read) } unless read == false
|
|
147
|
-
|
|
171
|
+
return if write == false
|
|
172
|
+
mock_object_class.define_writer(write)
|
|
173
|
+
write_method =
|
|
174
|
+
case field.type
|
|
175
|
+
in :object then ->(value) { object.send(write, field.form.as_written(value)) }
|
|
176
|
+
in :array then ->(value) {
|
|
177
|
+
items = value.respond_to?(:values) ? value.values : Array(value)
|
|
178
|
+
object.send(write, items.map { |v| field.form.as_written(v) })
|
|
179
|
+
}
|
|
180
|
+
in :scalar then ->(value) { object.send(write, value) }
|
|
181
|
+
end
|
|
182
|
+
field_methods_module.define_method(:"#{name}=", write_method)
|
|
148
183
|
end
|
|
149
184
|
|
|
150
185
|
def create_form_class_for(field_name)
|
|
@@ -160,5 +195,9 @@ module ModelFormFacade
|
|
|
160
195
|
include @field_methods_module
|
|
161
196
|
@field_methods_module
|
|
162
197
|
end
|
|
198
|
+
|
|
199
|
+
def mock_object_class
|
|
200
|
+
@mock_object_class ||= Class.new(MockObject)
|
|
201
|
+
end
|
|
163
202
|
end
|
|
164
203
|
end
|