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.
- checksums.yaml +8 -8
- data/Gemfile.lock +3 -3
- data/README.md +16 -17
- data/lib/freeform/form/date_params_filter.rb +34 -0
- data/lib/freeform/form/model.rb +56 -0
- data/lib/freeform/form/nested.rb +64 -39
- data/lib/freeform/form/property.rb +31 -75
- data/lib/freeform/form/validation.rb +48 -34
- data/lib/freeform/form.rb +31 -42
- data/lib/freeform/version.rb +1 -1
- data/spec/acceptance_spec.rb +140 -260
- data/spec/builder/builder_spec.rb +23 -41
- data/spec/builder/view_helper_spec.rb +7 -16
- data/spec/dummy/app/forms/project_form.rb +16 -2
- data/spec/dummy/app/models/company.rb +2 -2
- data/spec/dummy/app/models/milestone.rb +3 -3
- data/spec/dummy/app/models/project.rb +3 -3
- data/spec/dummy/app/models/task.rb +2 -2
- data/spec/dummy/db/migrate/20110710143903_initial_tables.rb +5 -5
- data/spec/dummy/db/schema.rb +6 -4
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/form/date_params_filter_spec.rb +51 -0
- data/spec/form/form_input_key_spec.rb +9 -11
- data/spec/form/model_spec.rb +244 -0
- data/spec/form/nested_spec.rb +108 -138
- data/spec/form/persistence_spec.rb +304 -0
- data/spec/form/property_spec.rb +104 -256
- data/spec/form/validation_spec.rb +114 -127
- data/spec/spec_helper.rb +6 -0
- metadata +10 -10
- data/spec/dummy/app/forms/milestone_form.rb +0 -4
- data/spec/dummy/app/forms/task_form.rb +0 -11
- data/spec/dummy/log/test.log +0 -111133
- data/spec/persistence_spec.rb +0 -645
data/spec/form/nested_spec.rb
CHANGED
@@ -3,161 +3,131 @@ require 'freeform/form/property'
|
|
3
3
|
require 'freeform/form/nested'
|
4
4
|
|
5
5
|
describe FreeForm::Nested do
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
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
|
-
|
46
|
-
|
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
|
-
|
72
|
-
|
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
|
-
|
76
|
-
|
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 "
|
82
|
-
|
83
|
-
|
84
|
-
|
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
|
-
|
88
|
-
|
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
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
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
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
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
|