freeform 1.0.11 → 2.0.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.
@@ -3,161 +3,131 @@ require 'freeform/form/property'
3
3
  require 'freeform/form/nested'
4
4
 
5
5
  describe FreeForm::Nested do
6
- describe "has_many", :has_many => true do
7
- let!(:nested_class) do
8
- klass = Class.new(Module) do
9
- include FreeForm::Property
10
- include FreeForm::Nested
6
+ let(:form_class) do
7
+ klass = Class.new(Module) do
8
+ include FreeForm::Model
9
+ include FreeForm::Property
10
+ include FreeForm::Nested
11
+
12
+ def initialize(h={})
13
+ h.each {|k,v| send("#{k}=",v)}
14
+ end
15
+
16
+ has_many :mailing_addresses, :default_initializer => :mailing_address_initializer do
11
17
  declared_model :address
12
-
13
18
  property :street, :on => :address
14
-
15
- def initialize(h={})
16
- h.each {|k,v| send("#{k}=",v)}
17
- end
18
19
  end
19
- # This wrapper just avoids CONST warnings
20
- v, $VERBOSE = $VERBOSE, nil
21
- Module.const_set("MailingAddressForm", klass)
22
- $VERBOSE = v
23
- klass
24
- end
25
20
 
26
- let!(:second_nested_class) do
27
- klass = Class.new(Module) do
28
- include FreeForm::Property
29
- include FreeForm::Nested
21
+ def mailing_address_initializer
22
+ { :address => OpenStruct.new(:id => Random.new.rand(1000000)) }
23
+ end
24
+
25
+ has_many :phone_numbers, :default_initializer => :phone_number_initializer do
30
26
  declared_model :phone
31
-
32
- property :number, :on => :phone
33
-
34
- def initialize(h={})
35
- h.each {|k,v| send("#{k}=",v)}
36
- end
27
+ property :number, :on => :phone
37
28
  end
38
- # This wrapper just avoids CONST warnings
39
- v, $VERBOSE = $VERBOSE, nil
40
- Module.const_set("PhoneNumberForm", klass)
41
- $VERBOSE = v
42
- klass
43
- end
44
29
 
45
- let(:form_class) do
46
- klass = Class.new(Module) do
47
- include FreeForm::Property
48
- include FreeForm::Nested
49
-
50
- def initialize(h={})
51
- h.each {|k,v| send("#{k}=",v)}
52
- end
53
-
54
- has_many :mailing_addresses, :class => Module::MailingAddressForm, :default_initializer => :mailing_address_initializer
55
- def mailing_address_initializer
56
- { :address => OpenStruct.new(:id => Random.new.rand(1000000)) }
57
- end
58
-
59
- has_many :phone_numbers, :class => Module::PhoneNumberForm, :default_initializer => :phone_number_initializer
60
- def phone_number_initializer
61
- { :phone => OpenStruct.new(:id => Random.new.rand(1000000)) }
62
- end
30
+ def phone_number_initializer
31
+ { :phone => OpenStruct.new(:id => Random.new.rand(1000000)) }
63
32
  end
64
- # This wrapper just avoids CONST warnings
65
- v, $VERBOSE = $VERBOSE, nil
66
- Module.const_set("DummyForm", klass)
67
- $VERBOSE = v
68
- klass
69
33
  end
34
+ # This wrapper just avoids CONST warnings
35
+ v, $VERBOSE = $VERBOSE, nil
36
+ Module.const_set("ParentForm", klass)
37
+ $VERBOSE = v
38
+ klass
39
+ end
70
40
 
71
- let(:form) do
72
- form_model = form_class.new
41
+ let(:form) do
42
+ form_model = form_class.new
43
+ end
44
+
45
+ describe "form class" do
46
+ it "has correct class" do
47
+ form.should be_a(Module::ParentForm)
73
48
  end
74
49
 
75
- describe "form class" do
76
- it "sets nested_form in models" do
77
- form_class.models.should eq([:mailing_addresses, :phone_numbers])
78
- end
50
+ it "has nested forms" do
51
+ form_class.nested_forms.should eq([Module::ParentForm::MailingAddress, Module::ParentForm::PhoneNumber])
79
52
  end
80
-
81
- describe "building nested models" do
82
- it "initializes with no nested models prebuilt" do
83
- form.mailing_addresses.should eq([])
84
- form.phone_numbers.should eq([])
53
+
54
+ describe "mailing address nested form class" do
55
+ let(:nested_form) { form_class.nested_forms.first.new }
56
+
57
+ it "should be a MailingAddress object" do
58
+ nested_form.should be_a(Module::ParentForm::MailingAddress)
85
59
  end
86
-
87
- context "with default initializer" do
88
- context "for mailing addresses" do
89
- it "allows nested_forms to be built" do
90
- form.build_mailing_addresses
91
- form.mailing_addresses.should be_an(Array)
92
- form.mailing_addresses.should_not be_empty
93
- form.mailing_addresses.first.should be_a(Module::MailingAddressForm)
94
- end
95
-
96
- it "does not add to other has_many array" do
97
- form.build_mailing_addresses
98
- form.phone_numbers.should eq([])
99
- end
100
-
101
- it "builds unique models" do
102
- form = form_class.new
103
- form.build_mailing_address
104
- form.build_mailing_address
105
- address_1 = form.mailing_addresses.first.address
106
- address_2 = form.mailing_addresses.last.address
107
- address_1.should_not eq(address_2)
108
- end
109
- end
110
-
111
- context "for phone numbers" do
112
- it "allows nested_forms to be built" do
113
- form.build_phone_number
114
- form.phone_numbers.should be_an(Array)
115
- form.phone_numbers.should_not be_empty
116
- form.phone_numbers.first.should be_a(Module::PhoneNumberForm)
117
- end
118
-
119
- it "does not add to other has_many array" do
120
- form.build_phone_numbers
121
- form.mailing_addresses.should eq([])
122
- end
123
-
124
- it "builds unique models" do
125
- form = form_class.new
126
- form.build_phone_number
127
- form.build_phone_number
128
- phone_1 = form.phone_numbers.first.phone
129
- phone_2 = form.phone_numbers.last.phone
130
- phone_1.should_not eq(phone_2)
131
- end
132
- end
60
+
61
+ it "should respond to property methods" do
62
+ nested_form.should respond_to(:street)
133
63
  end
134
-
135
- context "with custom initializer" do
136
- it "allows nested_forms to be built" do
137
- form.build_mailing_addresses(:address => OpenStruct.new)
138
- form.mailing_addresses.should be_an(Array)
139
- form.mailing_addresses.should_not be_empty
140
- form.mailing_addresses.first.should be_a(Module::MailingAddressForm)
141
- end
142
-
143
- it "allows nested_forms to be built with custom initializers" do
144
- form.build_mailing_address(:address => OpenStruct.new(:street => "1600 Pennsylvania Ave."))
145
- form.mailing_addresses.first.street.should eq("1600 Pennsylvania Ave.")
146
- end
64
+ end
65
+
66
+ describe "phone number nested form class" do
67
+ let(:nested_form) { form_class.nested_forms.last.new }
68
+
69
+ it "should be a PhoneNumber object" do
70
+ nested_form.should be_a(Module::ParentForm::PhoneNumber)
147
71
  end
72
+
73
+ it "should respond to property methods" do
74
+ nested_form.should respond_to(:number)
75
+ end
76
+ end
77
+ end
78
+
79
+ describe "building nested models" do
80
+ it "responds to mailing_addresses" do
81
+ form.should respond_to(:mailing_addresses)
82
+ end
83
+
84
+ it "responds to phone_numbers" do
85
+ form.should respond_to(:phone_numbers)
148
86
  end
149
-
150
- describe "setting attributes" do
151
- describe "nested attribute assignment" do
152
- let(:attributes) do
153
- { :mailing_addresses_attributes => { "0" => { :street => "123 Main St." } } }
154
- end
155
-
156
- it "assigns nested attributes" do
157
- form.fill(attributes)
158
- form.mailing_addresses.first.street.should eq("123 Main St.")
159
- end
87
+
88
+ it "initializes with no nested models prebuilt" do
89
+ form.mailing_addresses.should eq([])
90
+ form.phone_numbers.should eq([])
91
+ end
92
+
93
+ describe "building new nested models" do
94
+ it "can build new nested model" do
95
+ form.build_mailing_address
96
+ form.mailing_addresses.should_not be_empty
97
+ form.mailing_addresses.first.should be_a(Module::ParentForm::MailingAddress)
98
+ end
99
+
100
+ it "builds unique models" do
101
+ form.build_mailing_address
102
+ form.build_mailing_address
103
+ address_model_1 = form.mailing_addresses.first
104
+ address_model_2 = form.mailing_addresses.last
105
+ address_model_1.should_not eq(address_model_2)
106
+ address_model_1.address.should_not eq(address_model_2.address)
107
+ end
108
+
109
+ it "builds with correct default initializer" do
110
+ address_model = form.build_mailing_address
111
+ address_model.address.should be_a(OpenStruct)
112
+ end
113
+
114
+ it "builds with custom initializer" do
115
+ address_model = form.build_mailing_address({:address => Date.new})
116
+ address_model.address.should be_a(Date)
160
117
  end
161
- end
118
+ end
162
119
  end
120
+
121
+ describe "setting attributes" do
122
+ describe "nested attribute assignment" do
123
+ let(:attributes) do
124
+ { :mailing_addresses_attributes => { "0" => { :street => "123 Main St." } } }
125
+ end
126
+
127
+ it "assigns nested attributes" do
128
+ form.fill(attributes)
129
+ form.mailing_addresses.first.street.should eq("123 Main St.")
130
+ end
131
+ end
132
+ end
163
133
  end
@@ -0,0 +1,304 @@
1
+ require 'spec_helper'
2
+
3
+ describe FreeForm::Form do
4
+ let(:form_class) do
5
+ klass = Class.new(FreeForm::Form) do
6
+ form_input_key :task
7
+ form_models :task
8
+ validate_models
9
+ allow_destroy_on_save
10
+
11
+ property :name, :on => :task
12
+ property :start_date, :on => :task
13
+ property :end_date, :on => :task
14
+ validates :name, :presence => true
15
+
16
+ has_many :milestones do
17
+ form_input_key :milestone
18
+ form_model :milestone
19
+ validate_models
20
+ allow_destroy_on_save
21
+
22
+ property :name, :on => :milestone
23
+ end
24
+
25
+ def milestone_initializer
26
+ { :milestone => task.milestones.build }
27
+ end
28
+ end
29
+ # This wrapper just avoids CONST warnings
30
+ v, $VERBOSE = $VERBOSE, nil
31
+ Module.const_set("AcceptanceForm", klass)
32
+ $VERBOSE = v
33
+ klass
34
+ end
35
+
36
+ let(:company) { Company.create!(:name => "Demo Corporation") }
37
+ let(:project) { Project.create!(:owner => company, :name => "Widget", :due_date => Date.new(2014, 1, 1)) }
38
+ let(:task) { Task.new(:project => project) }
39
+
40
+ let(:form) do
41
+ form_class.new( :task => task ).tap do |f|
42
+ f.build_milestone
43
+ end
44
+ end
45
+
46
+ before(:each) { Milestone.destroy_all }
47
+
48
+ describe "form initialization", :initialization => true do
49
+ it "initializes with task model" do
50
+ form.task.should eq(task)
51
+ end
52
+
53
+ it "initializes with a milestone model" do
54
+ form.milestones.should_not be_empty
55
+ end
56
+ end
57
+
58
+ describe "saving", :saving => true do
59
+ context "with invalid attributes on primary form" do
60
+ let(:attributes) do {
61
+ :name => nil,
62
+ "start_date(1i)" => "2012",
63
+ "start_date(2i)" => "1",
64
+ "start_date(3i)" => "2",
65
+ "end_date(1i)" => "2011",
66
+ "end_date(2i)" => "12",
67
+ "end_date(3i)" => "15",
68
+ :milestones_attributes => {
69
+ "0" => {
70
+ :name => "milestone_1",
71
+ },
72
+ "1310201" => {
73
+ :name => "milestone_2",
74
+ }
75
+ } }
76
+ end
77
+
78
+ before(:each) do
79
+ form.fill(attributes)
80
+ end
81
+
82
+ it "should not be valid" do
83
+ form.should_not be_valid
84
+ end
85
+
86
+ describe "#save" do
87
+ it "should return false on 'save'" do
88
+ form.save.should be_false
89
+ end
90
+
91
+ it "should not persist task" do
92
+ form.save
93
+ task.should_not exist_in_database
94
+ end
95
+
96
+ it "should not save any Milestone objects" do
97
+ form.save
98
+ Milestone.all.size.should eq(0)
99
+ end
100
+ end
101
+
102
+ describe "#save!" do
103
+ it "should raise error on 'save!'" do
104
+ expect{ form.save! }.to raise_error(FreeForm::FormInvalid)
105
+ end
106
+ end
107
+ end
108
+
109
+ context "with invalid attributes on nested form" do
110
+ let(:attributes) do {
111
+ :name => "newtask",
112
+ "start_date(1i)" => "2012",
113
+ "start_date(2i)" => "1",
114
+ "start_date(3i)" => "2",
115
+ "end_date(1i)" => "2011",
116
+ "end_date(2i)" => "12",
117
+ "end_date(3i)" => "15",
118
+ :milestones_attributes => {
119
+ "0" => {
120
+ :name => "milestone_1",
121
+ },
122
+ "1310201" => {
123
+ :name => nil,
124
+ }
125
+ } }
126
+ end
127
+
128
+ before(:each) do
129
+ form.fill(attributes)
130
+ end
131
+
132
+ it "should not be valid" do
133
+ form.should_not be_valid
134
+ end
135
+
136
+ describe "#save" do
137
+ it "should return false on 'save'" do
138
+ form.save.should be_false
139
+ end
140
+
141
+ it "should not persist task" do
142
+ form.save
143
+ task.should_not exist_in_database
144
+ end
145
+
146
+ it "should not save any Milestone objects" do
147
+ form.save
148
+ Milestone.all.size.should eq(0)
149
+ end
150
+ end
151
+
152
+ describe "#save!" do
153
+ it "should raise error on 'save!'" do
154
+ expect{ form.save! }.to raise_error(FreeForm::FormInvalid)
155
+ end
156
+ end
157
+ end
158
+
159
+ context "with invalid attributes on destroyed nested form" do
160
+ let(:attributes) do {
161
+ :name => "newtask",
162
+ "start_date(1i)" => "2012",
163
+ "start_date(2i)" => "1",
164
+ "start_date(3i)" => "2",
165
+ "end_date(1i)" => "2011",
166
+ "end_date(2i)" => "12",
167
+ "end_date(3i)" => "15",
168
+ :milestones_attributes => {
169
+ "0" => {
170
+ :name => "milestone_1",
171
+ },
172
+ "1310201" => {
173
+ :name => nil,
174
+ :_destroy => "1",
175
+ }
176
+ } }
177
+ end
178
+
179
+ before(:each) do
180
+ form.fill(attributes)
181
+ end
182
+
183
+ it "should not be valid" do
184
+ form.should be_valid
185
+ end
186
+
187
+ describe "#save" do
188
+ it "should return true on 'save'" do
189
+ form.save.should be_true
190
+ end
191
+
192
+ it "should persist task" do
193
+ form.save
194
+ task.should exist_in_database
195
+ end
196
+
197
+ it "should save one Milestone object" do
198
+ form.save
199
+ Milestone.all.size.should eq(1)
200
+ end
201
+ end
202
+
203
+ describe "#save!" do
204
+ it "should not raise error on 'save!'" do
205
+ expect{ form.save! }.to_not raise_error
206
+ end
207
+ end
208
+ end
209
+
210
+ context "with valid attributes and multiple nested forms" do
211
+ let(:attributes) do {
212
+ :name => "newtask",
213
+ "start_date(1i)" => "2012",
214
+ "start_date(2i)" => "1",
215
+ "start_date(3i)" => "2",
216
+ "end_date(1i)" => "2011",
217
+ "end_date(2i)" => "12",
218
+ "end_date(3i)" => "15",
219
+ :milestones_attributes => {
220
+ "0" => {
221
+ :name => "milestone_1",
222
+ },
223
+ "1310201" => {
224
+ :name => "milestone_2",
225
+ },
226
+ "9837373" => {
227
+ :name => "milestone_3",
228
+ }
229
+ } }
230
+ end
231
+
232
+ before(:each) do
233
+ form.fill(attributes)
234
+ end
235
+
236
+ it "should not be valid" do
237
+ form.should be_valid
238
+ end
239
+
240
+ describe "#save" do
241
+ it "should return true on 'save'" do
242
+ form.save.should be_true
243
+ end
244
+
245
+ it "should persist task" do
246
+ form.save
247
+ task.should exist_in_database
248
+ end
249
+
250
+ it "should save three Milestone objects" do
251
+ form.save
252
+ Milestone.all.size.should eq(3)
253
+ end
254
+ end
255
+
256
+ describe "#save!" do
257
+ it "should not raise error on 'save!'" do
258
+ expect{ form.save! }.to_not raise_error
259
+ end
260
+ end
261
+ end
262
+ end
263
+
264
+ describe "destroying", :destroying => true do
265
+ context "without nested forms" do
266
+ let(:task) { Task.create!(:project => project, :name => "mytask", :start_date => Date.new(2011, 1, 1), :end_date => Date.new(2012, 1, 1)) }
267
+
268
+ let(:form) do
269
+ form_class.new( :task => task )
270
+ end
271
+
272
+ it "destroys all models in form" do
273
+ form.destroy
274
+ task.should_not exist_in_database
275
+ end
276
+ end
277
+
278
+ context "with nested forms" do
279
+ let(:task) { Task.create!(:project => project, :name => "mytask", :start_date => Date.new(2011, 1, 1), :end_date => Date.new(2012, 1, 1)) }
280
+ let(:milestone) do
281
+ task.milestones.build do |m|
282
+ m.name = "dummy_milestone"
283
+ m.save!
284
+ end
285
+ end
286
+
287
+ let(:form) do
288
+ form_class.new( :task => task ).tap do |f|
289
+ f.build_milestone(:milestone => milestone)
290
+ end
291
+ end
292
+
293
+ it "destroys all models in form" do
294
+ form.destroy
295
+ task.should_not exist_in_database
296
+ end
297
+
298
+ it "destroys all nested models" do
299
+ form.destroy
300
+ milestone.should_not exist_in_database
301
+ end
302
+ end
303
+ end
304
+ end