reform 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
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