reform 1.2.6 → 2.0.0.beta1
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/.travis.yml +6 -1
- data/CHANGES.md +14 -0
- data/Gemfile +3 -2
- data/README.md +225 -283
- data/Rakefile +27 -0
- data/TODO.md +12 -0
- data/database.sqlite3 +0 -0
- data/gemfiles/Gemfile.rails-3.0 +1 -0
- data/gemfiles/Gemfile.rails-3.1 +1 -0
- data/gemfiles/Gemfile.rails-3.2 +1 -0
- data/gemfiles/Gemfile.rails-4.0 +1 -0
- data/lib/reform.rb +0 -1
- data/lib/reform/contract.rb +64 -170
- data/lib/reform/contract/validate.rb +10 -13
- data/lib/reform/form.rb +74 -19
- data/lib/reform/form/active_model.rb +19 -14
- data/lib/reform/form/coercion.rb +1 -13
- data/lib/reform/form/composition.rb +2 -24
- data/lib/reform/form/multi_parameter_attributes.rb +43 -62
- data/lib/reform/form/populator.rb +85 -0
- data/lib/reform/form/prepopulate.rb +13 -43
- data/lib/reform/form/validate.rb +29 -90
- data/lib/reform/form/validation/unique_validator.rb +13 -0
- data/lib/reform/version.rb +1 -1
- data/reform.gemspec +7 -7
- data/test/active_model_test.rb +43 -0
- data/test/changed_test.rb +23 -51
- data/test/coercion_test.rb +1 -7
- data/test/composition_test.rb +128 -34
- data/test/contract_test.rb +27 -86
- data/test/feature_test.rb +43 -6
- data/test/fields_test.rb +2 -12
- data/test/form_builder_test.rb +28 -25
- data/test/form_option_test.rb +19 -0
- data/test/from_test.rb +0 -75
- data/test/inherit_test.rb +178 -117
- data/test/model_reflections_test.rb +1 -1
- data/test/populate_test.rb +226 -0
- data/test/prepopulator_test.rb +112 -0
- data/test/readable_test.rb +2 -4
- data/test/save_test.rb +56 -112
- data/test/setup_test.rb +48 -0
- data/test/skip_if_test.rb +5 -2
- data/test/skip_setter_and_getter_test.rb +54 -0
- data/test/test_helper.rb +3 -1
- data/test/uniqueness_test.rb +41 -0
- data/test/validate_test.rb +325 -289
- data/test/virtual_test.rb +1 -3
- data/test/writeable_test.rb +3 -4
- metadata +35 -39
- data/lib/reform/composition.rb +0 -63
- data/lib/reform/contract/setup.rb +0 -50
- data/lib/reform/form/changed.rb +0 -9
- data/lib/reform/form/sync.rb +0 -116
- data/lib/reform/representer.rb +0 -84
- data/test/empty_test.rb +0 -58
- data/test/form_composition_test.rb +0 -145
- data/test/nested_form_test.rb +0 -197
- data/test/prepopulate_test.rb +0 -85
- data/test/sync_option_test.rb +0 -83
- data/test/sync_test.rb +0 -56
data/test/virtual_test.rb
CHANGED
@@ -2,8 +2,6 @@ require 'test_helper'
|
|
2
2
|
|
3
3
|
class VirtualTest < MiniTest::Spec
|
4
4
|
class CreditCardForm < Reform::Form
|
5
|
-
reform_2_0!
|
6
|
-
|
7
5
|
property :credit_card_number, virtual: true # no read, no write, it's virtual.
|
8
6
|
end
|
9
7
|
|
@@ -12,7 +10,7 @@ class VirtualTest < MiniTest::Spec
|
|
12
10
|
it {
|
13
11
|
form.validate("credit_card_number" => "123")
|
14
12
|
|
15
|
-
form.credit_card_number.must_equal "123"
|
13
|
+
form.credit_card_number.must_equal "123" # this is still readable in the UI.
|
16
14
|
|
17
15
|
form.sync
|
18
16
|
|
data/test/writeable_test.rb
CHANGED
@@ -1,19 +1,18 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
class WriteableTest < MiniTest::Spec
|
3
|
+
class WriteableTest < MiniTest::Spec
|
4
4
|
Location = Struct.new(:country)
|
5
5
|
|
6
6
|
class LocationForm < Reform::Form
|
7
|
-
reform_2_0!
|
8
|
-
|
9
7
|
property :country, writeable: false
|
10
8
|
end
|
11
9
|
|
12
10
|
let (:loc) { Location.new("Australia") }
|
13
11
|
let (:form) { LocationForm.new(loc) }
|
14
12
|
|
15
|
-
it { form.country.must_equal "Australia" }
|
16
13
|
it do
|
14
|
+
form.country.must_equal "Australia"
|
15
|
+
|
17
16
|
form.validate("country" => "Germany") # this usually won't change when submitting.
|
18
17
|
form.country.must_equal "Germany"
|
19
18
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reform
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Sutterer
|
@@ -9,36 +9,36 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-06-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: representable
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- - "
|
18
|
+
- - ">="
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: 2.
|
20
|
+
version: 2.2.2
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
|
-
- - "
|
25
|
+
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: 2.
|
27
|
+
version: 2.2.2
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: disposable
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
32
|
- - "~>"
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: 0.
|
34
|
+
version: 0.1.2
|
35
35
|
type: :runtime
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
39
|
- - "~>"
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version: 0.
|
41
|
+
version: 0.1.2
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: uber
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -71,16 +71,16 @@ dependencies:
|
|
71
71
|
name: bundler
|
72
72
|
requirement: !ruby/object:Gem::Requirement
|
73
73
|
requirements:
|
74
|
-
- - "
|
74
|
+
- - ">="
|
75
75
|
- !ruby/object:Gem::Version
|
76
|
-
version: '
|
76
|
+
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
79
|
version_requirements: !ruby/object:Gem::Requirement
|
80
80
|
requirements:
|
81
|
-
- - "
|
81
|
+
- - ">="
|
82
82
|
- !ruby/object:Gem::Version
|
83
|
-
version: '
|
83
|
+
version: '0'
|
84
84
|
- !ruby/object:Gem::Dependency
|
85
85
|
name: rake
|
86
86
|
requirement: !ruby/object:Gem::Requirement
|
@@ -99,16 +99,16 @@ dependencies:
|
|
99
99
|
name: minitest
|
100
100
|
requirement: !ruby/object:Gem::Requirement
|
101
101
|
requirements:
|
102
|
-
- -
|
102
|
+
- - ">="
|
103
103
|
- !ruby/object:Gem::Version
|
104
|
-
version:
|
104
|
+
version: '0'
|
105
105
|
type: :development
|
106
106
|
prerelease: false
|
107
107
|
version_requirements: !ruby/object:Gem::Requirement
|
108
108
|
requirements:
|
109
|
-
- -
|
109
|
+
- - ">="
|
110
110
|
- !ruby/object:Gem::Version
|
111
|
-
version:
|
111
|
+
version: '0'
|
112
112
|
- !ruby/object:Gem::Dependency
|
113
113
|
name: activerecord
|
114
114
|
requirement: !ruby/object:Gem::Requirement
|
@@ -179,7 +179,7 @@ dependencies:
|
|
179
179
|
- - ">="
|
180
180
|
- !ruby/object:Gem::Version
|
181
181
|
version: '0'
|
182
|
-
description:
|
182
|
+
description: Form object decoupled from models.
|
183
183
|
email:
|
184
184
|
- apotonick@gmail.com
|
185
185
|
- heinleng@gmail.com
|
@@ -202,29 +202,26 @@ files:
|
|
202
202
|
- gemfiles/Gemfile.rails-4.0
|
203
203
|
- lib/reform.rb
|
204
204
|
- lib/reform/active_record.rb
|
205
|
-
- lib/reform/composition.rb
|
206
205
|
- lib/reform/contract.rb
|
207
206
|
- lib/reform/contract/errors.rb
|
208
|
-
- lib/reform/contract/setup.rb
|
209
207
|
- lib/reform/contract/validate.rb
|
210
208
|
- lib/reform/form.rb
|
211
209
|
- lib/reform/form/active_model.rb
|
212
210
|
- lib/reform/form/active_model/model_validations.rb
|
213
211
|
- lib/reform/form/active_record.rb
|
214
|
-
- lib/reform/form/changed.rb
|
215
212
|
- lib/reform/form/coercion.rb
|
216
213
|
- lib/reform/form/composition.rb
|
217
214
|
- lib/reform/form/json.rb
|
218
215
|
- lib/reform/form/model_reflections.rb
|
219
216
|
- lib/reform/form/module.rb
|
220
217
|
- lib/reform/form/multi_parameter_attributes.rb
|
218
|
+
- lib/reform/form/populator.rb
|
221
219
|
- lib/reform/form/prepopulate.rb
|
222
220
|
- lib/reform/form/save.rb
|
223
221
|
- lib/reform/form/scalar.rb
|
224
|
-
- lib/reform/form/sync.rb
|
225
222
|
- lib/reform/form/validate.rb
|
223
|
+
- lib/reform/form/validation/unique_validator.rb
|
226
224
|
- lib/reform/rails.rb
|
227
|
-
- lib/reform/representer.rb
|
228
225
|
- lib/reform/schema.rb
|
229
226
|
- lib/reform/twin.rb
|
230
227
|
- lib/reform/version.rb
|
@@ -262,19 +259,18 @@ files:
|
|
262
259
|
- test/dummy/db/test.sqlite3
|
263
260
|
- test/dummy/log/production.log
|
264
261
|
- test/dummy/log/server.log
|
265
|
-
- test/empty_test.rb
|
266
262
|
- test/errors_test.rb
|
267
263
|
- test/feature_test.rb
|
268
264
|
- test/fields_test.rb
|
269
265
|
- test/form_builder_test.rb
|
270
|
-
- test/
|
266
|
+
- test/form_option_test.rb
|
271
267
|
- test/form_test.rb
|
272
268
|
- test/from_test.rb
|
273
269
|
- test/inherit_test.rb
|
274
270
|
- test/model_reflections_test.rb
|
275
271
|
- test/model_validations_test.rb
|
276
|
-
- test/
|
277
|
-
- test/
|
272
|
+
- test/populate_test.rb
|
273
|
+
- test/prepopulator_test.rb
|
278
274
|
- test/rails/integration_test.rb
|
279
275
|
- test/read_only_test.rb
|
280
276
|
- test/readable_test.rb
|
@@ -283,12 +279,13 @@ files:
|
|
283
279
|
- test/representer_test.rb
|
284
280
|
- test/save_test.rb
|
285
281
|
- test/scalar_test.rb
|
282
|
+
- test/setup_test.rb
|
286
283
|
- test/skip_if_test.rb
|
284
|
+
- test/skip_setter_and_getter_test.rb
|
287
285
|
- test/skip_unchanged_test.rb
|
288
|
-
- test/sync_option_test.rb
|
289
|
-
- test/sync_test.rb
|
290
286
|
- test/test_helper.rb
|
291
287
|
- test/twin_test.rb
|
288
|
+
- test/uniqueness_test.rb
|
292
289
|
- test/validate_test.rb
|
293
290
|
- test/virtual_test.rb
|
294
291
|
- test/writeable_test.rb
|
@@ -307,16 +304,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
307
304
|
version: '0'
|
308
305
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
309
306
|
requirements:
|
310
|
-
- - "
|
307
|
+
- - ">"
|
311
308
|
- !ruby/object:Gem::Version
|
312
|
-
version:
|
309
|
+
version: 1.3.1
|
313
310
|
requirements: []
|
314
311
|
rubyforge_project:
|
315
|
-
rubygems_version: 2.
|
312
|
+
rubygems_version: 2.4.8
|
316
313
|
signing_key:
|
317
314
|
specification_version: 4
|
318
|
-
summary:
|
319
|
-
presentation, workflows and security.
|
315
|
+
summary: Form object decoupled from models with validation, population and presentation.
|
320
316
|
test_files:
|
321
317
|
- test/active_model_test.rb
|
322
318
|
- test/active_record_test.rb
|
@@ -351,19 +347,18 @@ test_files:
|
|
351
347
|
- test/dummy/db/test.sqlite3
|
352
348
|
- test/dummy/log/production.log
|
353
349
|
- test/dummy/log/server.log
|
354
|
-
- test/empty_test.rb
|
355
350
|
- test/errors_test.rb
|
356
351
|
- test/feature_test.rb
|
357
352
|
- test/fields_test.rb
|
358
353
|
- test/form_builder_test.rb
|
359
|
-
- test/
|
354
|
+
- test/form_option_test.rb
|
360
355
|
- test/form_test.rb
|
361
356
|
- test/from_test.rb
|
362
357
|
- test/inherit_test.rb
|
363
358
|
- test/model_reflections_test.rb
|
364
359
|
- test/model_validations_test.rb
|
365
|
-
- test/
|
366
|
-
- test/
|
360
|
+
- test/populate_test.rb
|
361
|
+
- test/prepopulator_test.rb
|
367
362
|
- test/rails/integration_test.rb
|
368
363
|
- test/read_only_test.rb
|
369
364
|
- test/readable_test.rb
|
@@ -372,12 +367,13 @@ test_files:
|
|
372
367
|
- test/representer_test.rb
|
373
368
|
- test/save_test.rb
|
374
369
|
- test/scalar_test.rb
|
370
|
+
- test/setup_test.rb
|
375
371
|
- test/skip_if_test.rb
|
372
|
+
- test/skip_setter_and_getter_test.rb
|
376
373
|
- test/skip_unchanged_test.rb
|
377
|
-
- test/sync_option_test.rb
|
378
|
-
- test/sync_test.rb
|
379
374
|
- test/test_helper.rb
|
380
375
|
- test/twin_test.rb
|
376
|
+
- test/uniqueness_test.rb
|
381
377
|
- test/validate_test.rb
|
382
378
|
- test/virtual_test.rb
|
383
379
|
- test/writeable_test.rb
|
data/lib/reform/composition.rb
DELETED
@@ -1,63 +0,0 @@
|
|
1
|
-
require 'disposable/composition'
|
2
|
-
|
3
|
-
# TODO: replace that with lazy Twin and Composition from Disposable.
|
4
|
-
module Reform
|
5
|
-
class Expose
|
6
|
-
include Disposable::Composition
|
7
|
-
|
8
|
-
# DISCUSS: this might be moved to Disposable::Twin::Expose.
|
9
|
-
class << self
|
10
|
-
# Builder for a concrete Composition class with configurations from the form's representer.
|
11
|
-
def from(representer)
|
12
|
-
options = {}
|
13
|
-
|
14
|
-
representer.representable_attrs.each do |definition|
|
15
|
-
process_definition!(options, definition)
|
16
|
-
end
|
17
|
-
|
18
|
-
Class.new(self).tap do |composition| # for 1.8 compat. you're welcome.
|
19
|
-
composition.map(options)
|
20
|
-
# puts composition@map.inspect
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
def process_definition!(options, definition)
|
26
|
-
options[:model] ||= []
|
27
|
-
options[:model] << [definition[:private_name], definition.name].compact
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
# Keeps composition of models and knows how to transform a plain hash into a nested hash.
|
33
|
-
class Composition < Expose
|
34
|
-
|
35
|
-
# DISCUSS: this might be moved to Disposable::Twin::Composition.
|
36
|
-
class << self
|
37
|
-
# Builder for a concrete Composition class with configurations from the form's representer.
|
38
|
-
def process_definition!(options, definition)
|
39
|
-
options[definition[:on]] ||= []
|
40
|
-
options[definition[:on]] << [definition[:private_name], definition.name].compact
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def save
|
45
|
-
each.collect { |model| model.save }.all?
|
46
|
-
end
|
47
|
-
|
48
|
-
def nested_hash_for(attrs)
|
49
|
-
{}.tap do |hsh|
|
50
|
-
attrs.each do |name, val|
|
51
|
-
#obj = self.class.model_for_property(name)
|
52
|
-
config = self.class.instance_variable_get(:@map)[name.to_sym]
|
53
|
-
|
54
|
-
model = config[:model]
|
55
|
-
method = config[:method]
|
56
|
-
|
57
|
-
hsh[model] ||= {}
|
58
|
-
hsh[model][method] = val
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
module Reform
|
2
|
-
class Contract
|
3
|
-
module Setup
|
4
|
-
def initialize(model)
|
5
|
-
@model = model # we need this for #save.
|
6
|
-
@fields = setup_fields # delegate all methods to Fields instance.
|
7
|
-
end
|
8
|
-
|
9
|
-
# Setup#to_hash will create a nested hash of property values from the model.
|
10
|
-
# Nested properties will be recursively wrapped in a form instance.
|
11
|
-
def setup_representer
|
12
|
-
self.class.representer(:setup) do |dfn| # only nested forms.
|
13
|
-
dfn.merge!(
|
14
|
-
:representable => false, # don't call #to_hash, only prepare.
|
15
|
-
:prepare => lambda { |model, args| args.binding[:form].new(model) } # wrap nested properties in form.
|
16
|
-
)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def setup_fields
|
21
|
-
representer = setup_representer.new(aliased_model)
|
22
|
-
options = setup_options(Reform::Representer::Options[]) # handles :empty.
|
23
|
-
|
24
|
-
# populate the internal @fields set with data from the model.
|
25
|
-
create_fields(mapper.fields, representer.to_hash(options))
|
26
|
-
end
|
27
|
-
|
28
|
-
def create_fields(field_names, fields)
|
29
|
-
Fields.new(field_names, fields)
|
30
|
-
end
|
31
|
-
|
32
|
-
module SetupOptions
|
33
|
-
def setup_options(options)
|
34
|
-
options
|
35
|
-
end
|
36
|
-
end
|
37
|
-
include SetupOptions
|
38
|
-
|
39
|
-
|
40
|
-
module Readable
|
41
|
-
def setup_options(options)
|
42
|
-
empty_fields = mapper.representable_attrs.find_all { |d| d[:_readable] == false }.collect { |d| d.name.to_sym }
|
43
|
-
|
44
|
-
options.exclude!(empty_fields)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
include Readable
|
48
|
-
end
|
49
|
-
end # Setup
|
50
|
-
end
|
data/lib/reform/form/changed.rb
DELETED
data/lib/reform/form/sync.rb
DELETED
@@ -1,116 +0,0 @@
|
|
1
|
-
# #sync!
|
2
|
-
# 1. assign scalars to model (respecting virtual, excluded attributes)
|
3
|
-
# 2. call sync! on nested
|
4
|
-
module Reform::Form::Sync
|
5
|
-
def sync_models(options={})
|
6
|
-
sync!(options)
|
7
|
-
end
|
8
|
-
alias_method :sync, :sync_models
|
9
|
-
|
10
|
-
# reading from fields allows using readers in form for presentation
|
11
|
-
# and writers still pass to fields in #validate????
|
12
|
-
def sync!(options) # semi-public.
|
13
|
-
options = Reform::Representer::Options[options.merge(:form => self)] # options local for this form, only.
|
14
|
-
|
15
|
-
input = sync_hash(options)
|
16
|
-
# if aliased_model was a proper Twin, we could do changed? stuff there.
|
17
|
-
|
18
|
-
options.delete(:exclude) # TODO: can we use 2 options?
|
19
|
-
|
20
|
-
dynamic_sync_representer.new(aliased_model).from_hash(input, options) # sync properties to Song.
|
21
|
-
|
22
|
-
model
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
# Transforms form input into what actually gets written to model.
|
28
|
-
# output: {title: "Mint Car", hit: <Form>}
|
29
|
-
def input_representer
|
30
|
-
self.class.representer(:input, :all => true) do |dfn|
|
31
|
-
if dfn[:form]
|
32
|
-
dfn.merge!(
|
33
|
-
:representable => false,
|
34
|
-
:prepare => lambda { |obj, *| obj },
|
35
|
-
)
|
36
|
-
else
|
37
|
-
dfn.merge!(:render_nil => true) # do sync nil values back to the model for scalars.
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
# Writes input to model.
|
43
|
-
def sync_representer
|
44
|
-
self.class.representer(:sync, :all => true) do |dfn|
|
45
|
-
if dfn[:form]
|
46
|
-
dfn.merge!(
|
47
|
-
:instance => lambda { |fragment, *| fragment }, # use model's nested property for syncing.
|
48
|
-
# FIXME: do we allow options for #sync for nested forms?
|
49
|
-
:deserialize => lambda { |object, *| model = object.sync!({}) } # sync! returns the synced model.
|
50
|
-
# representable's :setter will do collection=([..]) or property=(..) for us on the model.
|
51
|
-
)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
# This representer inherits from sync_representer and add functionality on top of that.
|
57
|
-
# It allows running custom dynamic blocks for properties when syncing.
|
58
|
-
def dynamic_sync_representer
|
59
|
-
self.class.representer(:dynamic_sync, superclass: sync_representer, :all => true) do |dfn|
|
60
|
-
next unless setter = dfn[:sync]
|
61
|
-
|
62
|
-
setter_proc = lambda do |value, options|
|
63
|
-
if options.binding[:sync] == true # sync: true will call the runtime lambda from the options hash.
|
64
|
-
options.user_options[options.binding.name.to_sym].call(value, options)
|
65
|
-
next
|
66
|
-
end
|
67
|
-
|
68
|
-
# evaluate the :sync block in form context (should we do that everywhere?).
|
69
|
-
options.user_options[:form].instance_exec(value, options, &setter)
|
70
|
-
end
|
71
|
-
|
72
|
-
dfn.merge!(:setter => setter_proc)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
|
77
|
-
# API: semi-public.
|
78
|
-
module SyncHash
|
79
|
-
# This hash goes into the Writer that writes properties back to the model. It only contains "writeable" attributes.
|
80
|
-
def sync_hash(options)
|
81
|
-
input_representer.new(fields).to_hash(options)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
include SyncHash
|
85
|
-
|
86
|
-
|
87
|
-
# Excludes :virtual and readonly properties from #sync in this form.
|
88
|
-
module Writeable
|
89
|
-
def sync_hash(options)
|
90
|
-
readonly_fields = mapper.fields { |dfn| dfn[:_writeable] == false }
|
91
|
-
|
92
|
-
options.exclude!(readonly_fields.map(&:to_sym))
|
93
|
-
|
94
|
-
super
|
95
|
-
end
|
96
|
-
end
|
97
|
-
include Writeable
|
98
|
-
|
99
|
-
|
100
|
-
# This will skip unchanged properties in #sync. To use this for all nested form do as follows.
|
101
|
-
#
|
102
|
-
# class SongForm < Reform::Form
|
103
|
-
# feature Synd::SkipUnchanged
|
104
|
-
module SkipUnchanged
|
105
|
-
def sync_hash(options)
|
106
|
-
# DISCUSS: we currently don't track if nested forms have changed (only their attributes). that's why i include them all here, which
|
107
|
-
# is additional sync work/slightly wrong. solution: allow forms to form.changed? not sure how to do that with collections.
|
108
|
-
scalars = mapper.fields { |dfn| !dfn[:form] }
|
109
|
-
unchanged = scalars - changed.keys
|
110
|
-
|
111
|
-
# exclude unchanged scalars, nested forms and changed scalars still go in here!
|
112
|
-
options.exclude!(unchanged.map(&:to_sym))
|
113
|
-
super
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|