snusnu-dm-accepts_nested_attributes 0.0.6 → 0.10.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.
Files changed (33) hide show
  1. data/Manifest.txt +13 -8
  2. data/Rakefile +2 -3
  3. data/TODO +5 -0
  4. data/lib/dm-accepts_nested_attributes.rb +7 -14
  5. data/lib/dm-accepts_nested_attributes/error_collecting.rb +35 -0
  6. data/lib/dm-accepts_nested_attributes/model.rb +132 -0
  7. data/lib/dm-accepts_nested_attributes/resource.rb +218 -29
  8. data/lib/dm-accepts_nested_attributes/save.rb +13 -0
  9. data/lib/dm-accepts_nested_attributes/transactional_save.rb +15 -0
  10. data/lib/dm-accepts_nested_attributes/version.rb +1 -1
  11. data/spec/fixtures/person.rb +8 -0
  12. data/spec/fixtures/profile.rb +9 -0
  13. data/spec/fixtures/project.rb +8 -0
  14. data/spec/fixtures/project_membership.rb +8 -0
  15. data/spec/fixtures/task.rb +9 -0
  16. data/spec/integration/belongs_to_spec.rb +10 -134
  17. data/spec/integration/has_1_spec.rb +9 -121
  18. data/spec/integration/has_n_spec.rb +10 -149
  19. data/spec/integration/has_n_through_spec.rb +10 -162
  20. data/spec/{shared → lib}/rspec_tmbundle_support.rb +1 -1
  21. data/spec/shared/belongs_to_spec.rb +127 -0
  22. data/spec/shared/has_1_spec.rb +103 -0
  23. data/spec/shared/has_n_spec.rb +114 -0
  24. data/spec/shared/has_n_through_spec.rb +139 -0
  25. data/spec/spec_helper.rb +12 -9
  26. data/spec/unit/accepts_nested_attributes_for_spec.rb +39 -118
  27. data/tasks/changelog.rb +18 -0
  28. data/tasks/spec.rb +0 -1
  29. metadata +19 -14
  30. data/lib/dm-accepts_nested_attributes/association_proxies.rb +0 -55
  31. data/lib/dm-accepts_nested_attributes/association_validation.rb +0 -49
  32. data/lib/dm-accepts_nested_attributes/nested_attributes.rb +0 -350
  33. data/spec/unit/resource_spec.rb +0 -174
@@ -2,137 +2,7 @@ require 'pathname'
2
2
  require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
3
 
4
4
  describe DataMapper::NestedAttributes do
5
-
6
- describe "every accessible has(n) association with a valid reject_if proc", :shared => true do
7
-
8
- it "should not allow to create a new task via Project#tasks_attributes" do
9
- @project.save
10
- Project.all.size.should == 1
11
- Task.all.size.should == 0
12
-
13
- @project.tasks_attributes = { 'new_1' => { :name => 'write specs' } }
14
- @project.tasks.should be_empty
15
- @project.save
16
- Project.all.size.should == 1
17
- Task.all.size.should == 0
18
- end
19
-
20
- end
21
-
22
- describe "every accessible has(n) association with no reject_if proc", :shared => true do
23
-
24
- it "should allow to create a new task via Project#tasks_attributes" do
25
- @project.save
26
- Project.all.size.should == 1
27
- Task.all.size.should == 0
28
-
29
- @project.tasks_attributes = { 'new_1' => { :name => 'write specs' } }
30
- @project.tasks.should_not be_empty
31
- @project.tasks.first.name.should == 'write specs'
32
- @project.save
33
- @project.tasks.first.should == Task.first
34
- Project.all.size.should == 1
35
- Task.all.size.should == 1
36
- Task.first.name.should == 'write specs'
37
- end
38
-
39
- it "should allow to update an existing task via Project#tasks_attributes" do
40
- @project.save
41
- task = Task.create(:project => @project, :name => 'write specs')
42
- Project.all.size.should == 1
43
- Task.all.size.should == 1
44
-
45
- @project.tasks_attributes = { task.id.to_s => { :id => task.id, :name => 'write more specs' } }
46
- @project.tasks.should_not be_empty
47
- @project.tasks.first.name.should == 'write more specs'
48
- @project.save
49
-
50
- Project.all.size.should == 1
51
- Task.all.size.should == 1
52
- Task.first.name.should == 'write more specs'
53
- end
54
-
55
- it "should perform atomic commits" do
56
- Project.all.size.should == 0
57
- Task.all.size.should == 0
58
-
59
- @project.name = nil # will fail because of validations
60
- @project.tasks_attributes = { 'new_1' => { :name => 'write specs' } }
61
- @project.tasks.should_not be_empty
62
- @project.tasks.first.name.should == 'write specs'
63
- @project.save
64
- @project.should be_new_record
65
- @project.tasks.all? { |t| t.should be_new_record }
66
- Project.all.size.should == 0
67
- Task.all.size.should == 0
68
-
69
- # TODO write specs for xxx_attributes= method that test
70
- # if same hash keys properly get overwritten and not end up being multiple records
71
- # (which obviously is the case right now)
72
-
73
- @project.name = 'dm-accepts_nested_attributes'
74
- @project.tasks_attributes = { 'new_1' => { :name => nil } } # will fail because of validations
75
- @project.tasks.should_not be_empty
76
- @project.tasks.first.name.should be_nil
77
- @project.save
78
- @project.should be_new_record
79
- @project.tasks.all? { |t| t.should be_new_record }
80
- Project.all.size.should == 0
81
- Task.all.size.should == 0
82
- end
83
-
84
- end
85
-
86
- describe "every accessible has(n) association with :allow_destroy => false", :shared => true do
87
-
88
- it "should not allow to delete an existing task via Profile#tasks_attributes" do
89
- @project.save
90
- task = Task.create(:project => @project, :name => 'write specs')
91
-
92
- Project.all.size.should == 1
93
- Task.all.size.should == 1
94
-
95
- @project.reload
96
- @project.tasks_attributes = { '1' => { :id => task.id, :_delete => true } }
97
- @project.save
98
-
99
- Project.all.size.should == 1
100
- Task.all.size.should == 1
101
- end
102
-
103
- end
104
-
105
- describe "every accessible has(n) association with :allow_destroy => true", :shared => true do
106
-
107
- it "should allow to delete an existing task via Profile#tasks_attributes" do
108
- @project.save
109
- task = Task.create(:project => @project, :name => 'write specs')
110
-
111
- Project.all.size.should == 1
112
- Task.all.size.should == 1
113
-
114
- @project.reload
115
- @project.tasks_attributes = { '1' => { :id => task.id, :_delete => true } }
116
- @project.save
117
-
118
- Project.all.size.should == 1
119
- Task.all.size.should == 0
120
- end
121
-
122
- end
123
-
124
- describe "every accessible has(n) association with a nested attributes reader", :shared => true do
125
-
126
- it "should return the attributes written to Project#task_attributes from the Project#task_attributes reader" do
127
- @project.tasks_attributes.should be_nil
128
-
129
- @project.tasks_attributes = { 'new_1' => { :name => 'write specs' } }
130
-
131
- @project.tasks_attributes.should == { 'new_1' => { :name => 'write specs' } }
132
- end
133
5
 
134
- end
135
-
136
6
  describe "Project.has(n, :tasks)" do
137
7
 
138
8
  include OneToManyHelpers
@@ -148,10 +18,10 @@ describe DataMapper::NestedAttributes do
148
18
  Project.accepts_nested_attributes_for :tasks
149
19
  @project = Project.new :name => 'trippings'
150
20
  end
151
-
21
+
22
+ it_should_behave_like "every accessible has(n) association"
152
23
  it_should_behave_like "every accessible has(n) association with no reject_if proc"
153
24
  it_should_behave_like "every accessible has(n) association with :allow_destroy => false"
154
- it_should_behave_like "every accessible has(n) association with a nested attributes reader"
155
25
 
156
26
  end
157
27
 
@@ -162,7 +32,8 @@ describe DataMapper::NestedAttributes do
162
32
  Project.accepts_nested_attributes_for :tasks, :allow_destroy => false
163
33
  @project = Project.new :name => 'trippings'
164
34
  end
165
-
35
+
36
+ it_should_behave_like "every accessible has(n) association"
166
37
  it_should_behave_like "every accessible has(n) association with no reject_if proc"
167
38
  it_should_behave_like "every accessible has(n) association with :allow_destroy => false"
168
39
 
@@ -175,26 +46,14 @@ describe DataMapper::NestedAttributes do
175
46
  Project.accepts_nested_attributes_for :tasks, :allow_destroy => true
176
47
  @project = Project.new :name => 'trippings'
177
48
  end
178
-
49
+
50
+ it_should_behave_like "every accessible has(n) association"
179
51
  it_should_behave_like "every accessible has(n) association with no reject_if proc"
180
52
  it_should_behave_like "every accessible has(n) association with :allow_destroy => true"
181
53
 
182
54
  end
183
55
 
184
56
  describe "accepts_nested_attributes_for :tasks, " do
185
-
186
- describe ":reject_if => :foo" do
187
-
188
- before(:each) do
189
- clear_data
190
- Project.accepts_nested_attributes_for :tasks, :reject_if => :foo
191
- @project = Project.new :name => 'trippings'
192
- end
193
-
194
- it_should_behave_like "every accessible has(n) association with no reject_if proc"
195
- it_should_behave_like "every accessible has(n) association with :allow_destroy => false"
196
-
197
- end
198
57
 
199
58
  describe ":reject_if => lambda { |attrs| true }" do
200
59
 
@@ -203,7 +62,8 @@ describe DataMapper::NestedAttributes do
203
62
  Project.accepts_nested_attributes_for :tasks, :reject_if => lambda { |attrs| true }
204
63
  @project = Project.new :name => 'trippings'
205
64
  end
206
-
65
+
66
+ it_should_behave_like "every accessible has(n) association"
207
67
  it_should_behave_like "every accessible has(n) association with a valid reject_if proc"
208
68
  it_should_behave_like "every accessible has(n) association with :allow_destroy => false"
209
69
 
@@ -216,7 +76,8 @@ describe DataMapper::NestedAttributes do
216
76
  Project.accepts_nested_attributes_for :tasks, :reject_if => lambda { |attrs| false }
217
77
  @project = Project.new :name => 'trippings'
218
78
  end
219
-
79
+
80
+ it_should_behave_like "every accessible has(n) association"
220
81
  it_should_behave_like "every accessible has(n) association with no reject_if proc"
221
82
  it_should_behave_like "every accessible has(n) association with :allow_destroy => false"
222
83
 
@@ -2,150 +2,7 @@ require 'pathname'
2
2
  require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
3
 
4
4
  describe DataMapper::NestedAttributes do
5
-
6
- describe "every accessible has(n, :through) association with a valid reject_if proc", :shared => true do
7
-
8
- it "should not allow to create a new project via Person#projects_attributes" do
9
- @person.save
10
- Person.all.size.should == 1
11
- ProjectMembership.all.size.should == 0
12
- Project.all.size.should == 0
13
-
14
- @person.projects_attributes = { 'new_1' => { :name => 'dm-accepts_nested_attributes' } }
15
- @person.projects.should be_empty
16
- @person.save
17
-
18
- Person.all.size.should == 1
19
- ProjectMembership.all.size.should == 0
20
- Project.all.size.should == 0
21
- end
22
-
23
- end
24
-
25
- describe "every accessible has(n, :through) association with no reject_if proc", :shared => true do
26
-
27
- it "should allow to create a new project via Person#projects_attributes" do
28
- @person.save
29
- Person.all.size.should == 1
30
- ProjectMembership.all.size.should == 0
31
- Project.all.size.should == 0
32
-
33
- @person.projects_attributes = { 'new_1' => { :name => 'dm-accepts_nested_attributes' } }
34
- @person.projects.should_not be_empty
35
- @person.projects.first.name.should == 'dm-accepts_nested_attributes'
36
- @person.save
37
- @person.projects.first.should == Project.first
38
-
39
- Person.all.size.should == 1
40
- ProjectMembership.all.size.should == 1
41
- Project.all.size.should == 1
42
-
43
- Project.first.name.should == 'dm-accepts_nested_attributes'
44
- end
45
-
46
- it "should allow to update an existing project via Person#projects_attributes" do
47
- @person.save
48
- project = Project.create(:name => 'dm-accepts_nested_attributes')
49
- project_membership = ProjectMembership.create(:person => @person, :project => project)
50
- Person.all.size.should == 1
51
- Project.all.size.should == 1
52
- ProjectMembership.all.size.should == 1
53
-
54
- @person.reload
55
-
56
- @person.projects_attributes = { project.id.to_s => { :id => project.id, :name => 'still dm-accepts_nested_attributes' } }
57
- @person.projects.should_not be_empty
58
- @person.projects.first.name.should == 'still dm-accepts_nested_attributes'
59
- @person.save
60
-
61
- Person.all.size.should == 1
62
- ProjectMembership.all.size.should == 1
63
- Project.all.size.should == 1
64
-
65
- Project.first.name.should == 'still dm-accepts_nested_attributes'
66
- end
67
-
68
- it "should perform atomic commits" do
69
-
70
- @person.projects_attributes = { 'new_1' => { :name => nil } } # should fail because of validations
71
- @person.projects.should be_empty
72
- @person.save
73
- @person.projects.should be_empty
74
-
75
- Person.all.size.should == 1
76
- ProjectMembership.all.size.should == 0
77
- Project.all.size.should == 0
78
-
79
- @person.name = nil # should fail because of validations
80
- @person.projects_attributes = { 'new_1' => { :name => nil } }
81
- @person.projects.should be_empty
82
- @person.save
83
- @person.projects.should be_empty
84
-
85
- Person.all.size.should == 0
86
- ProjectMembership.all.size.should == 0
87
- Project.all.size.should == 0
88
-
89
- end
90
-
91
- end
92
-
93
- describe "every accessible has(n, :through) association with :allow_destroy => false", :shared => true do
94
-
95
- it "should not allow to delete an existing project via Person#projects_attributes" do
96
- @person.save
97
- project = Project.create(:name => 'dm-accepts_nested_attributes')
98
- project_membership = ProjectMembership.create(:person => @person, :project => project)
99
-
100
- Person.all.size.should == 1
101
- ProjectMembership.all.size.should == 1
102
- Project.all.size.should == 1
103
-
104
- @person.reload
105
- @person.projects_attributes = { '1' => { :id => project.id, :_delete => true } }
106
- @person.save
107
-
108
- Person.all.size.should == 1
109
- ProjectMembership.all.size.should == 1
110
- Project.all.size.should == 1
111
- end
112
-
113
- end
114
-
115
- describe "every accessible has(n, :through) association with :allow_destroy => true", :shared => true do
116
-
117
- it "should allow to delete an existing project via Person#projects_attributes" do
118
- @person.save
119
- project = Project.create(:name => 'dm-accepts_nested_attributes')
120
- project_membership = ProjectMembership.create(:person => @person, :project => project)
121
-
122
- Person.all.size.should == 1
123
- ProjectMembership.all.size.should == 1
124
- Project.all.size.should == 1
125
-
126
- @person.reload
127
- @person.projects_attributes = { '1' => { :id => project.id, :_delete => true } }
128
- @person.save
129
-
130
- Person.all.size.should == 1
131
- ProjectMembership.all.size.should == 0
132
- Project.all.size.should == 0
133
- end
134
-
135
- end
136
-
137
- describe "every accessible has(n, :through) association with a nested attributes reader", :shared => true do
138
5
 
139
- it "should return the attributes written to Person#projects_attributes from the Person#projects_attributes reader" do
140
- @person.projects_attributes.should be_nil
141
-
142
- @person.projects_attributes = { 'new_1' => { :name => 'write specs' } }
143
-
144
- @person.projects_attributes.should == { 'new_1' => { :name => 'write specs' } }
145
- end
146
-
147
- end
148
-
149
6
  describe "Person.has(n, :projects, :through => :project_memberships)" do
150
7
 
151
8
  include ManyToManyHelpers
@@ -161,10 +18,10 @@ describe DataMapper::NestedAttributes do
161
18
  Person.accepts_nested_attributes_for :projects
162
19
  @person = Person.new :name => 'snusnu'
163
20
  end
164
-
21
+
22
+ it_should_behave_like "every accessible has(n, :through) association"
165
23
  it_should_behave_like "every accessible has(n, :through) association with no reject_if proc"
166
24
  it_should_behave_like "every accessible has(n, :through) association with :allow_destroy => false"
167
- it_should_behave_like "every accessible has(n, :through) association with a nested attributes reader"
168
25
 
169
26
  end
170
27
 
@@ -175,7 +32,8 @@ describe DataMapper::NestedAttributes do
175
32
  Person.accepts_nested_attributes_for :projects, :allow_destroy => false
176
33
  @person = Person.new :name => 'snusnu'
177
34
  end
178
-
35
+
36
+ it_should_behave_like "every accessible has(n, :through) association"
179
37
  it_should_behave_like "every accessible has(n, :through) association with no reject_if proc"
180
38
  it_should_behave_like "every accessible has(n, :through) association with :allow_destroy => false"
181
39
 
@@ -188,26 +46,14 @@ describe DataMapper::NestedAttributes do
188
46
  Person.accepts_nested_attributes_for :projects, :allow_destroy => true
189
47
  @person = Person.new :name => 'snusnu'
190
48
  end
191
-
49
+
50
+ it_should_behave_like "every accessible has(n, :through) association"
192
51
  it_should_behave_like "every accessible has(n, :through) association with no reject_if proc"
193
52
  it_should_behave_like "every accessible has(n, :through) association with :allow_destroy => true"
194
53
 
195
54
  end
196
55
 
197
56
  describe "accepts_nested_attributes_for :projects, " do
198
-
199
- describe ":reject_if => :foo" do
200
-
201
- before(:each) do
202
- clear_data
203
- Person.accepts_nested_attributes_for :projects, :reject_if => :foo
204
- @person = Person.new :name => 'snusnu'
205
- end
206
-
207
- it_should_behave_like "every accessible has(n, :through) association with no reject_if proc"
208
- it_should_behave_like "every accessible has(n, :through) association with :allow_destroy => false"
209
-
210
- end
211
57
 
212
58
  describe ":reject_if => lambda { |attrs| true }" do
213
59
 
@@ -216,7 +62,8 @@ describe DataMapper::NestedAttributes do
216
62
  Person.accepts_nested_attributes_for :projects, :reject_if => lambda { |attrs| true }
217
63
  @person = Person.new :name => 'snusnu'
218
64
  end
219
-
65
+
66
+ it_should_behave_like "every accessible has(n, :through) association"
220
67
  it_should_behave_like "every accessible has(n, :through) association with a valid reject_if proc"
221
68
  it_should_behave_like "every accessible has(n, :through) association with :allow_destroy => false"
222
69
 
@@ -229,7 +76,8 @@ describe DataMapper::NestedAttributes do
229
76
  Person.accepts_nested_attributes_for :projects, :reject_if => lambda { |attrs| false }
230
77
  @person = Person.new :name => 'snusnu'
231
78
  end
232
-
79
+
80
+ it_should_behave_like "every accessible has(n, :through) association"
233
81
  it_should_behave_like "every accessible has(n, :through) association with no reject_if proc"
234
82
  it_should_behave_like "every accessible has(n, :through) association with :allow_destroy => false"
235
83
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  module RSpecTmBundleHelpers
6
6
 
7
- class TextmateRspecLogger < DataMapper::Logger
7
+ class TextmateRspecLogger < Extlib::Logger
8
8
  def prep_msg(message, level)
9
9
  "#{super}<br />"
10
10
  end
@@ -0,0 +1,127 @@
1
+ describe "every accessible belongs_to association", :shared => true do
2
+
3
+ it "should allow to update an existing person via Profile#person_attributes" do
4
+ Profile.all.size.should == 0
5
+ Person.all.size.should == 0
6
+
7
+ person = Person.create(:name => 'Martin')
8
+ @profile.person = person
9
+ @profile.save.should be_true
10
+
11
+ Profile.all.size.should == 1
12
+ Person.all.size.should == 1
13
+ Person.first.name.should == 'Martin'
14
+
15
+ @profile.person_attributes = { :id => person.id, :name => 'Martin Gamsjaeger' }
16
+ @profile.save.should be_true
17
+
18
+ Profile.all.size.should == 1
19
+ Person.all.size.should == 1
20
+ Person.first.name.should == 'Martin Gamsjaeger'
21
+ end
22
+
23
+ it "should perform atomic commits" do
24
+ Profile.all.size.should == 0
25
+ Person.all.size.should == 0
26
+
27
+ # related resource is invalid
28
+ @profile.person_attributes = { :name => nil }
29
+ @profile.save.should be_false
30
+
31
+ Profile.all.size.should == 0
32
+ Person.all.size.should == 0
33
+
34
+ # self is invalid
35
+ @profile.nick = nil
36
+ @profile.person_attributes = { :name => 'Martin' }
37
+ @profile.save.should be_false
38
+
39
+ Profile.all.size.should == 0
40
+ Person.all.size.should == 0
41
+ end
42
+
43
+ it "should return the attributes written to Profile#person_attributes from the Profile#person_attributes reader" do
44
+ @profile.person_attributes.should be_nil
45
+ @profile.person_attributes = { :name => 'Martin' }
46
+ @profile.person_attributes.should == { :name => 'Martin' }
47
+ end
48
+
49
+ end
50
+
51
+ describe "every accessible belongs_to association with a valid reject_if proc", :shared => true do
52
+
53
+ it "should not allow to create a new person via Profile#person_attributes" do
54
+ Profile.all.size.should == 0
55
+ Person.all.size.should == 0
56
+
57
+ @profile.person_attributes = { :name => 'Martin' }
58
+ @profile.save.should be_false
59
+
60
+ Profile.all.size.should == 0
61
+ Person.all.size.should == 0
62
+ end
63
+
64
+ end
65
+
66
+ describe "every accessible belongs_to association with no reject_if proc", :shared => true do
67
+
68
+ it "should allow to create a new person via Profile#person_attributes" do
69
+ Profile.all.size.should == 0
70
+ Person.all.size.should == 0
71
+
72
+ @profile.person_attributes = { :name => 'Martin' }
73
+ @profile.save.should be_true
74
+
75
+ Profile.all.size.should == 1
76
+ Person.all.size.should == 1
77
+ Person.first.name.should == 'Martin'
78
+ end
79
+
80
+ end
81
+
82
+ describe "every accessible belongs_to association with :allow_destroy => false", :shared => true do
83
+
84
+ it "should not allow to delete an existing person via Profile#person_attributes" do
85
+ Profile.all.size.should == 0
86
+ Person.all.size.should == 0
87
+
88
+ person = Person.create(:name => 'Martin')
89
+ @profile.person = person
90
+ @profile.save.should be_true
91
+
92
+ Profile.all.size.should == 1
93
+ Person.all.size.should == 1
94
+
95
+ @profile.person_attributes = { :id => person.id, :_delete => true }
96
+ @profile.save
97
+
98
+ Profile.all.size.should == 1
99
+ Person.all.size.should == 1
100
+ end
101
+
102
+ end
103
+
104
+ describe "every accessible belongs_to association with :allow_destroy => true", :shared => true do
105
+
106
+ it "should allow to delete an existing person via Profile#person_attributes" do
107
+ Profile.all.size.should == 0
108
+ Person.all.size.should == 0
109
+
110
+ person = Person.create(:name => 'Martin')
111
+ @profile.person = person
112
+ @profile.save.should be_true
113
+
114
+ Profile.all.size.should == 1
115
+ Person.all.size.should == 1
116
+
117
+ @profile.person_attributes = { :id => person.id, :_delete => true }
118
+ @profile.save
119
+
120
+ Profile.all.size.should == 1 # project.person_id must not be nil
121
+ Person.all.size.should == 1
122
+
123
+ # TODO also test this behavior in situations where setting the FK to nil is allowed
124
+
125
+ end
126
+
127
+ end