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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b232b1d3bcc6dea9226b28873a60bba7a56772df
4
- data.tar.gz: 4b987843362c2cc4ff3349304f0672182437a828
3
+ metadata.gz: 7858098ed982e9c00c56016f1678e26f4c43b9e6
4
+ data.tar.gz: e518cbde390737b8308ce6aa41d398b6b48b2533
5
5
  SHA512:
6
- metadata.gz: 1c7eefc137c219075f02c5ff89035fadb1868b7b693ac828b100f63621f55158f0dc05b6a497efc935193f670438a42675487ebacdd5dfacf9d0c8a990a53911
7
- data.tar.gz: 70f13e49731d80f0645f4467fb5521cce5b34ee9fe7490b23f0b2d6f79f66630ecec4902a2d17d2758a1b861804ad437ce205f3fcba693a084274e89f6662139
6
+ metadata.gz: 0d4cb6de758aeb2892ee47bb69c8f9bb061f184b8088b9eac294ed3add2e72d364b5425206b9720c671892b1926be13bff7d9a3d7a3ac818381468c9115db695
7
+ data.tar.gz: 868a33c66a5a2225da3a12596f7c1f703e10403a1ef7353393d237ae368b6be55148d9eb8a2fe3bdda8e1744100d3e6d668b224226001997e19d029269747d2f
data/CHANGES.md CHANGED
@@ -1,4 +1,10 @@
1
- h3. 0.2.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
- h3. 0.2.0
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
- h3. 0.1.3
27
+ ## 0.1.3
22
28
 
23
29
  * Altered `reform/rails` to conditionally load `ActiveRecord` code and created `reform/active_record`.
24
30
 
25
- h3. 0.1.2
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
- h3. 0.1.1
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
- h3. 0.1.0
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. If you're using Rails but for some reason wanna use the pure reform, `require reform/form`, only.
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
- if attr.options[:form_collection] # FIXME: why no array?
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
 
@@ -36,7 +36,7 @@ class Reform::Form
36
36
 
37
37
  def save(*)
38
38
  super.tap do
39
- model.save # DISCUSS: should we implement nested saving here?
39
+ model.save unless block_given? # DISCUSS: should we implement nested saving here?
40
40
  end
41
41
  end
42
42
 
@@ -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] = definition.options.delete(:extend)
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.
@@ -1,3 +1,3 @@
1
1
  module Reform
2
- VERSION = "0.2.1"
2
+ VERSION = "0.2.2"
3
3
  end
@@ -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
- let (:form) { form_class.new(OpenStruct.new(:artist => Artist.new, :songs => [OpenStruct.new])) }
53
- # TODO: test when keys are missing!
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" => ""}})
@@ -57,11 +57,18 @@ class ActiveRecordTest < MiniTest::Spec
57
57
 
58
58
  describe "#save" do
59
59
  # TODO: test 1-n?
60
- it "calls AR#save" do
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
@@ -17,4 +17,4 @@ module Dummy
17
17
  end
18
18
  end
19
19
 
20
- require "reform/rails"
20
+ #require "reform/rails" # FIXME: this has to happen automatically in the rake test_rails run.
@@ -57,7 +57,7 @@ class NestedFormTest < MiniTest::Spec
57
57
  "hit" =>{"title" => "Sacrifice"},
58
58
  "title" =>"Second Heat",
59
59
  "songs" => [{"title" => "Scarified"}])
60
- } # TODO: test empty/non-present songs
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.1
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-10-30 00:00:00.000000000 Z
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