reform 0.2.1 → 0.2.2
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/CHANGES.md +12 -6
- data/README.md +20 -2
- data/database.sqlite3 +0 -0
- data/lib/reform/form/active_model.rb +12 -5
- data/lib/reform/form/active_record.rb +1 -1
- data/lib/reform/form/multi_parameter_attributes.rb +36 -0
- data/lib/reform/form.rb +5 -3
- data/lib/reform/version.rb +1 -1
- data/test/active_model_test.rb +22 -2
- data/test/active_record_test.rb +8 -1
- data/test/dummy/config/application.rb +1 -1
- data/test/nested_form_test.rb +41 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7858098ed982e9c00c56016f1678e26f4c43b9e6
|
4
|
+
data.tar.gz: e518cbde390737b8308ce6aa41d398b6b48b2533
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d4cb6de758aeb2892ee47bb69c8f9bb061f184b8088b9eac294ed3add2e72d364b5425206b9720c671892b1926be13bff7d9a3d7a3ac818381468c9115db695
|
7
|
+
data.tar.gz: 868a33c66a5a2225da3a12596f7c1f703e10403a1ef7353393d237ae368b6be55148d9eb8a2fe3bdda8e1744100d3e6d668b224226001997e19d029269747d2f
|
data/CHANGES.md
CHANGED
@@ -1,4 +1,10 @@
|
|
1
|
-
|
1
|
+
## 0.2.2
|
2
|
+
|
3
|
+
* Fix a bug where `form.save do .. end` would call `model.save` even though a block was given. This no longer happens, if there's a block to `#save`, you have to manually save data (ActiveRecord environment, only).
|
4
|
+
* `#validate` doesn't blow up anymore when input data is missing for a nested property or collection.
|
5
|
+
* Allow `form: SongForm` to specify an explicit form class instead of using an inline form for nested properties.
|
6
|
+
|
7
|
+
## 0.2.1
|
2
8
|
|
3
9
|
* `ActiveRecord::i18n_scope` now returns `activerecord`.
|
4
10
|
* `Form#save` now calls save on the model in `ActiveRecord` context.
|
@@ -9,7 +15,7 @@ h3. 0.2.1
|
|
9
15
|
* Move `setup` and `save` logic into respective representer classes. This might break your code in case you overwrite private reform classes.
|
10
16
|
|
11
17
|
|
12
|
-
|
18
|
+
## 0.2.0
|
13
19
|
|
14
20
|
* Added nested property and collection for `has_one` and `has_many` relationships. . Note that this currently works only 1-level deep.
|
15
21
|
* Renamed `Reform::Form::DSL` to `Reform::Form::Composition` and deprecated `DSL`.
|
@@ -18,21 +24,21 @@ h3. 0.2.0
|
|
18
24
|
* `Form.new` now accepts one argument, only: the model/composition. If you want to create your own representer, inject it by overriding `Form#mapper`. Note that this won't create property accessors for you.
|
19
25
|
* `Form::ActiveModel` no longer creates accessors to your represented models, e.g. having `property :title, on: :song` doesn't allow `form.song` anymore. This is because the actual model and the form's state might differ, so please use `form.title` directly.
|
20
26
|
|
21
|
-
|
27
|
+
## 0.1.3
|
22
28
|
|
23
29
|
* Altered `reform/rails` to conditionally load `ActiveRecord` code and created `reform/active_record`.
|
24
30
|
|
25
|
-
|
31
|
+
## 0.1.2
|
26
32
|
|
27
33
|
* `Form#to_model` is now delegated to model.
|
28
34
|
* Coercion with virtus works.
|
29
35
|
|
30
|
-
|
36
|
+
## 0.1.1
|
31
37
|
|
32
38
|
* Added `reform/rails` that requires everything you need (even in other frameworks :).
|
33
39
|
* Added `Form::ActiveRecord` that gives you `validates_uniqueness_with`. Note that this is strongly coupled to your database, thou.
|
34
40
|
* Merged a lot of cleanups from sweet @parndt <3.
|
35
41
|
|
36
|
-
|
42
|
+
## 0.1.0
|
37
43
|
|
38
44
|
* Oh yeah.
|
data/README.md
CHANGED
@@ -402,8 +402,12 @@ Nesting forms only requires readers for the nested properties as `Album#songs`.
|
|
402
402
|
|
403
403
|
Check out [@gogogarret](https://twitter.com/GoGoGarrett/)'s [sample Rails app](https://github.com/gogogarrett/reform_example) using Reform.
|
404
404
|
|
405
|
-
Rails and Reform work out-of-the-box.
|
405
|
+
Rails and Reform work together out-of-the-box.
|
406
406
|
|
407
|
+
However, you should know about two things.
|
408
|
+
|
409
|
+
1. In case you explicitely _don't_ want to have automatic support for `ActiveRecord` and form builder: `require reform/form`, only.
|
410
|
+
2. In some setups around Rails 4 the `Form::ActiveRecord` module is not loaded properly, usually triggering a `NoMethodError` saying `undefined method 'model'`. If that happened to you, `require 'reform/rails'` manually at the bottom of your `config/application.rb`.
|
407
411
|
|
408
412
|
## ActiveRecord Compatibility
|
409
413
|
|
@@ -451,13 +455,27 @@ class SongForm < Reform::Form
|
|
451
455
|
end
|
452
456
|
```
|
453
457
|
|
454
|
-
|
455
458
|
## Security
|
456
459
|
|
457
460
|
By explicitely defining the form layout using `::property` there is no more need for protecting from unwanted input. `strong_parameter` or `
|
458
461
|
attr_accessible` become obsolete. Reform will simply ignore undefined incoming parameters.
|
459
462
|
|
460
463
|
|
464
|
+
## Additional Features
|
465
|
+
|
466
|
+
### Nesting Without Inline Representers
|
467
|
+
|
468
|
+
When nesting form, you usually use a so-called inline form doing `property :song do .. end`.
|
469
|
+
|
470
|
+
Sometimes you wanna specify an explicit form rather than using an inline form. Use the `form:` option here.
|
471
|
+
|
472
|
+
```ruby
|
473
|
+
property :song, form: SongForm`
|
474
|
+
```
|
475
|
+
|
476
|
+
The nested `SongForm` is a stand-alone form class you have to provide.
|
477
|
+
|
478
|
+
|
461
479
|
## Support
|
462
480
|
|
463
481
|
If you run into any trouble chat with us on irc.freenode.org#trailblazer.
|
data/database.sqlite3
CHANGED
Binary file
|
@@ -24,15 +24,22 @@ module Reform::Form::ActiveModel
|
|
24
24
|
# DISCUSS: #validate should actually expect the complete params hash and then pick the right key as it knows the form name.
|
25
25
|
# however, this would cause confusion?
|
26
26
|
mapper.new(self).nested_forms do |attr, model| # FIXME: make this simpler.
|
27
|
-
|
28
|
-
params[attr.name] = params["#{attr.name}_attributes"].values
|
29
|
-
else
|
30
|
-
params[attr.name] = params["#{attr.name}_attributes"]# DISCUSS: delete old key? override existing?
|
31
|
-
end
|
27
|
+
rename_nested_param_for!(params, attr)
|
32
28
|
end
|
33
29
|
|
34
30
|
super
|
35
31
|
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def rename_nested_param_for!(params, attr)
|
35
|
+
nested_name = "#{attr.name}_attributes"
|
36
|
+
return unless params.has_key?(nested_name)
|
37
|
+
|
38
|
+
value = params["#{attr.name}_attributes"]
|
39
|
+
value = value.values if attr.options[:form_collection]
|
40
|
+
|
41
|
+
params[attr.name] = value
|
42
|
+
end
|
36
43
|
end
|
37
44
|
|
38
45
|
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Reform::Form
|
2
|
+
module MultiParameterAttributes
|
3
|
+
class DateParamsFilter
|
4
|
+
def call(params)
|
5
|
+
date_attributes = {}
|
6
|
+
|
7
|
+
params.each do |attribute, value|
|
8
|
+
if value.is_a?(Hash)
|
9
|
+
call(value) # TODO: #validate should only handle local form params.
|
10
|
+
elsif matches = attribute.match(/^(\w+)\(.i\)$/)
|
11
|
+
date_attribute = matches[1]
|
12
|
+
date_attributes[date_attribute] = params_to_date(
|
13
|
+
params.delete("#{date_attribute}(1i)"),
|
14
|
+
params.delete("#{date_attribute}(2i)"),
|
15
|
+
params.delete("#{date_attribute}(3i)")
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
params.merge!(date_attributes)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def params_to_date(year, month, day)
|
24
|
+
day ||= 1 # FIXME: is that really what we want? test.
|
25
|
+
Date.new(year.to_i, month.to_i, day.to_i) # TODO: test fails.
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def validate(params)
|
30
|
+
# TODO: make it cleaner to hook into essential reform steps.
|
31
|
+
DateParamsFilter.new.call(params)
|
32
|
+
|
33
|
+
super
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/reform/form.rb
CHANGED
@@ -20,7 +20,8 @@ module Reform
|
|
20
20
|
process_options(name, options, &block)
|
21
21
|
|
22
22
|
definition = representer_class.property(name, options, &block)
|
23
|
-
setup_form_definition(definition) if block_given?
|
23
|
+
setup_form_definition(definition) if block_given? or options[:form]
|
24
|
+
|
24
25
|
create_accessor(name)
|
25
26
|
end
|
26
27
|
|
@@ -35,7 +36,7 @@ module Reform
|
|
35
36
|
end
|
36
37
|
|
37
38
|
def setup_form_definition(definition)
|
38
|
-
definition.options[:form]
|
39
|
+
definition.options[:form] ||= definition.options.delete(:extend)
|
39
40
|
|
40
41
|
definition.options[:parse_strategy] = :sync
|
41
42
|
definition.options[:instance] = true # just to make typed? work
|
@@ -82,9 +83,10 @@ module Reform
|
|
82
83
|
errors.merge!(form.errors, prefix)
|
83
84
|
false
|
84
85
|
end
|
85
|
-
|
86
86
|
end
|
87
87
|
include ValidateMethods
|
88
|
+
require 'reform/form/multi_parameter_attributes'
|
89
|
+
include MultiParameterAttributes # TODO: make features dynamic.
|
88
90
|
|
89
91
|
def save
|
90
92
|
# DISCUSS: we should never hit @mapper here (which writes to the models) when a block is passed.
|
data/lib/reform/version.rb
CHANGED
data/test/active_model_test.rb
CHANGED
@@ -45,12 +45,15 @@ class FormBuilderCompatTest < MiniTest::Spec
|
|
45
45
|
|
46
46
|
collection :songs do
|
47
47
|
property :title
|
48
|
+
property :release_date
|
48
49
|
validates :title, :presence => true
|
49
50
|
end
|
50
51
|
end
|
51
52
|
}
|
52
|
-
|
53
|
-
|
53
|
+
|
54
|
+
let (:song) { OpenStruct.new }
|
55
|
+
let (:form) { form_class.new(OpenStruct.new(
|
56
|
+
:artist => Artist.new(:name => "Propagandhi"), :songs => [song])) }
|
54
57
|
|
55
58
|
it "respects _attributes params hash" do
|
56
59
|
form.validate("artist_attributes" => {"name" => "Blink 182"},
|
@@ -60,11 +63,28 @@ class FormBuilderCompatTest < MiniTest::Spec
|
|
60
63
|
form.songs.first.title.must_equal "Damnit"
|
61
64
|
end
|
62
65
|
|
66
|
+
it "allows nested collection and property to be missing" do
|
67
|
+
form.validate({})
|
68
|
+
|
69
|
+
form.artist.name.must_equal "Propagandhi"
|
70
|
+
|
71
|
+
form.songs.size.must_equal 1
|
72
|
+
form.songs[0].model.must_equal song # this is a weird test.
|
73
|
+
end
|
74
|
+
|
63
75
|
it "defines _attributes= setter so Rails' FB works properly" do
|
64
76
|
form.must_respond_to("artist_attributes=")
|
65
77
|
form.must_respond_to("songs_attributes=")
|
66
78
|
end
|
67
79
|
|
80
|
+
it "accepts deconstructed date parameters" do
|
81
|
+
form.validate("artist_attributes" => {"name" => "Blink 182"},
|
82
|
+
"songs_attributes" => {"0" => {"title" => "Damnit", "release_date(1i)" => "1997",
|
83
|
+
"release_date(2i)" => "9", "release_date(3i)" => "27"}})
|
84
|
+
|
85
|
+
form.songs.first.release_date.must_equal Date.new(1997, 9, 27)
|
86
|
+
end
|
87
|
+
|
68
88
|
it "returns flat errors hash" do
|
69
89
|
form.validate("artist_attributes" => {"name" => ""},
|
70
90
|
"songs_attributes" => {"0" => {"title" => ""}})
|
data/test/active_record_test.rb
CHANGED
@@ -57,11 +57,18 @@ class ActiveRecordTest < MiniTest::Spec
|
|
57
57
|
|
58
58
|
describe "#save" do
|
59
59
|
# TODO: test 1-n?
|
60
|
-
it "calls
|
60
|
+
it "calls model.save" do
|
61
61
|
Artist.delete_all
|
62
62
|
form.validate("name" => "Bad Religion")
|
63
63
|
form.save
|
64
64
|
Artist.where(:name => "Bad Religion").size.must_equal 1
|
65
65
|
end
|
66
|
+
|
67
|
+
it "doesn't call model.save when block is given" do
|
68
|
+
Artist.delete_all
|
69
|
+
form.validate("name" => "Bad Religion")
|
70
|
+
form.save {}
|
71
|
+
Artist.where(:name => "Bad Religion").size.must_equal 0
|
72
|
+
end
|
66
73
|
end
|
67
74
|
end
|
data/test/nested_form_test.rb
CHANGED
@@ -57,7 +57,7 @@ class NestedFormTest < MiniTest::Spec
|
|
57
57
|
"hit" =>{"title" => "Sacrifice"},
|
58
58
|
"title" =>"Second Heat",
|
59
59
|
"songs" => [{"title" => "Scarified"}])
|
60
|
-
}
|
60
|
+
}
|
61
61
|
|
62
62
|
it "updates internal Fields" do
|
63
63
|
data = {}
|
@@ -104,6 +104,15 @@ class NestedFormTest < MiniTest::Spec
|
|
104
104
|
song.title.must_equal "Sacrifice"
|
105
105
|
songs.first.title.must_equal "Scarified"
|
106
106
|
end
|
107
|
+
|
108
|
+
describe "with invalid args" do
|
109
|
+
it "allows empty collection values" do
|
110
|
+
form.validate({})
|
111
|
+
|
112
|
+
form.songs.size.must_equal 1
|
113
|
+
form.songs[0].title.must_equal "Scarified"
|
114
|
+
end
|
115
|
+
end
|
107
116
|
end
|
108
117
|
|
109
118
|
# describe "with aliased nested form name" do
|
@@ -119,6 +128,37 @@ class NestedFormTest < MiniTest::Spec
|
|
119
128
|
# end
|
120
129
|
# end
|
121
130
|
|
131
|
+
class ExplicitNestedFormTest < MiniTest::Spec
|
132
|
+
let (:song) { OpenStruct.new(:title => "Downtown") }
|
133
|
+
let (:album) do
|
134
|
+
OpenStruct.new(
|
135
|
+
:title => "Blackhawks Over Los Angeles",
|
136
|
+
:hit => song,
|
137
|
+
)
|
138
|
+
end
|
139
|
+
let (:form) { AlbumForm.new(album) }
|
140
|
+
|
141
|
+
class SongForm < Reform::Form
|
142
|
+
property :title
|
143
|
+
validates_presence_of :title
|
144
|
+
end
|
145
|
+
|
146
|
+
class AlbumForm < Reform::Form
|
147
|
+
property :title
|
148
|
+
|
149
|
+
property :hit, :form => SongForm #, :parse_strategy => :sync, :instance => true
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
it "allows rendering" do
|
154
|
+
form.hit.title.must_equal "Downtown"
|
155
|
+
end
|
156
|
+
|
157
|
+
it { form.validate({"hit" => {"title" => ""}})
|
158
|
+
form.errors[:"hit.title"].must_equal(["can't be blank"])
|
159
|
+
}
|
160
|
+
end
|
161
|
+
|
122
162
|
class UnitTest < self
|
123
163
|
it "keeps Forms for form collection" do
|
124
164
|
form.send(:fields).songs.must_be_kind_of Reform::Form::Forms
|
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: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Sutterer
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-12-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: representable
|
@@ -166,6 +166,7 @@ files:
|
|
166
166
|
- lib/reform/form/active_record.rb
|
167
167
|
- lib/reform/form/coercion.rb
|
168
168
|
- lib/reform/form/composition.rb
|
169
|
+
- lib/reform/form/multi_parameter_attributes.rb
|
169
170
|
- lib/reform/form/virtual_attributes.rb
|
170
171
|
- lib/reform/rails.rb
|
171
172
|
- lib/reform/representer.rb
|