snusnu-dm-accepts_nested_attributes 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,7 +3,18 @@ module DataMapper
3
3
 
4
4
  module TransactionalSave
5
5
 
6
- def save(*args)
6
+ ##
7
+ # Overrides @see DataMapper::Resource#save to perform inside a transaction.
8
+ # The current implementation simply wraps the saving of the complete object tree
9
+ # inside a transaction and rolls back in case any exceptions are raised,
10
+ # or any of the calls to
11
+ #
12
+ # @see DataMapper::Resource#save
13
+ #
14
+ # @return [true, false]
15
+ # true if all related resources were saved properly
16
+ #
17
+ def save(*)
7
18
  saved = false
8
19
  transaction { |t| t.rollback unless saved = super }
9
20
  saved
@@ -1,7 +1,7 @@
1
1
  module DataMapper
2
2
  module NestedAttributes
3
3
 
4
- VERSION = '0.10.0'.freeze
4
+ VERSION = '0.11.0'.freeze
5
5
 
6
6
  end
7
7
  end
@@ -1,6 +1,7 @@
1
1
  class Person
2
2
 
3
3
  include DataMapper::Resource
4
+ extend ConstraintSupport
4
5
 
5
6
  # properties
6
7
 
@@ -9,8 +10,19 @@ class Person
9
10
 
10
11
  # associations
11
12
 
12
- has 1, :profile
13
- has n, :project_memberships
14
- has n, :projects, :through => :project_memberships
13
+ has 1, :profile,
14
+ constraint_options(:destroy)
15
+
16
+ # has 1, :address,
17
+ # :through => :profile
18
+
19
+ has n, :project_memberships,
20
+ constraint_options(:destroy)
21
+
22
+ has n, :projects,
23
+ :through => :project_memberships
24
+
25
+ # has n, :tasks,
26
+ # :through => :projects
15
27
 
16
28
  end
@@ -13,4 +13,6 @@ class Profile
13
13
 
14
14
  belongs_to :person
15
15
 
16
+ has 1, :address
17
+
16
18
  end
@@ -1,6 +1,7 @@
1
1
  class Project
2
2
 
3
3
  include DataMapper::Resource
4
+ extend ConstraintSupport
4
5
 
5
6
  # properties
6
7
 
@@ -9,8 +10,13 @@ class Project
9
10
 
10
11
  # associations
11
12
 
12
- has n, :tasks
13
- has n, :project_memberships
14
- has n, :people, :through => :project_memberships
15
-
13
+ has n, :tasks,
14
+ constraint_options(:destroy)
15
+
16
+ has n, :project_memberships,
17
+ constraint_options(:destroy)
18
+
19
+ has n, :people,
20
+ :through => :project_memberships
21
+
16
22
  end
@@ -0,0 +1,11 @@
1
+ module ConstraintSupport
2
+
3
+ def constraint_options(type)
4
+ if DataMapper.const_defined?('Constraints')
5
+ { :constraint => type }
6
+ else
7
+ {}
8
+ end
9
+ end
10
+
11
+ end
@@ -55,6 +55,10 @@ describe "every accessible belongs_to association with a valid reject_if proc",
55
55
  Person.all.size.should == 0
56
56
 
57
57
  @profile.person_attributes = { :name => 'Martin' }
58
+
59
+ Profile.all.size.should == 0
60
+ Person.all.size.should == 0
61
+
58
62
  @profile.save.should be_false
59
63
 
60
64
  Profile.all.size.should == 0
@@ -70,6 +74,10 @@ describe "every accessible belongs_to association with no reject_if proc", :shar
70
74
  Person.all.size.should == 0
71
75
 
72
76
  @profile.person_attributes = { :name => 'Martin' }
77
+
78
+ Profile.all.size.should == 0
79
+ Person.all.size.should == 0
80
+
73
81
  @profile.save.should be_true
74
82
 
75
83
  Profile.all.size.should == 1
@@ -87,12 +95,16 @@ describe "every accessible belongs_to association with :allow_destroy => false",
87
95
 
88
96
  person = Person.create(:name => 'Martin')
89
97
  @profile.person = person
90
- @profile.save.should be_true
98
+ @profile.save
91
99
 
92
100
  Profile.all.size.should == 1
93
101
  Person.all.size.should == 1
94
102
 
95
103
  @profile.person_attributes = { :id => person.id, :_delete => true }
104
+
105
+ Profile.all.size.should == 1
106
+ Person.all.size.should == 1
107
+
96
108
  @profile.save
97
109
 
98
110
  Profile.all.size.should == 1
@@ -115,10 +127,13 @@ describe "every accessible belongs_to association with :allow_destroy => true",
115
127
  Person.all.size.should == 1
116
128
 
117
129
  @profile.person_attributes = { :id => person.id, :_delete => true }
130
+
131
+ Profile.all.size.should == 1
132
+ Person.all.size.should == 1
133
+
118
134
  @profile.save
119
135
 
120
- Profile.all.size.should == 1 # project.person_id must not be nil
121
- Person.all.size.should == 1
136
+ Person.all.size.should == 0
122
137
 
123
138
  # TODO also test this behavior in situations where setting the FK to nil is allowed
124
139
 
@@ -5,6 +5,9 @@ describe "every accessible has(1) association", :shared => true do
5
5
  profile = Profile.create(:person_id => @person.id, :nick => 'snusnu')
6
6
  @person.reload
7
7
 
8
+ Person.all.size.should == 1
9
+ Profile.all.size.should == 1
10
+
8
11
  @person.profile_attributes = { :id => profile.id, :nick => 'still snusnu somehow' }
9
12
  @person.save.should be_true
10
13
 
@@ -13,24 +16,6 @@ describe "every accessible has(1) association", :shared => true do
13
16
  Profile.first.nick.should == 'still snusnu somehow'
14
17
  end
15
18
 
16
- it "should perform atomic commits" do
17
-
18
- # related resource is invalid
19
- @person.profile_attributes = { :nick => nil } # will fail because of validations
20
- @person.save.should be_false
21
-
22
- Person.all.size.should == 0
23
- Profile.all.size.should == 0
24
-
25
- # self is invalid
26
- @person.name = nil # will fail because of validations
27
- @person.profile_attributes = { :nick => 'snusnu' }
28
- @person.save.should be_false
29
-
30
- Person.all.size.should == 0
31
- Profile.all.size.should == 0
32
- end
33
-
34
19
  it "should return the attributes written to Person#profile_attributes from the Person#profile_attributes reader" do
35
20
  @person.profile_attributes.should be_nil
36
21
  @person.profile_attributes = { :nick => 'snusnu' }
@@ -61,6 +46,10 @@ describe "every accessible has(1) association with no reject_if proc", :shared =
61
46
  Profile.all.size.should == 0
62
47
 
63
48
  @person.profile_attributes = { :nick => 'snusnu' }
49
+
50
+ Person.all.size.should == 0
51
+ Profile.all.size.should == 0
52
+
64
53
  @person.save.should be_true
65
54
 
66
55
  Person.all.size.should == 1
@@ -68,6 +57,24 @@ describe "every accessible has(1) association with no reject_if proc", :shared =
68
57
  Profile.first.nick.should == 'snusnu'
69
58
  end
70
59
 
60
+ it "should perform atomic commits" do
61
+
62
+ # related resource is invalid
63
+ @person.profile_attributes = { :nick => nil } # will fail because of validations
64
+ @person.save.should be_false
65
+
66
+ Person.all.size.should == 0
67
+ Profile.all.size.should == 0
68
+
69
+ # self is invalid
70
+ @person.name = nil # will fail because of validations
71
+ @person.profile_attributes = { :nick => 'snusnu' }
72
+ @person.save.should be_false
73
+
74
+ Person.all.size.should == 0
75
+ Profile.all.size.should == 0
76
+ end
77
+
71
78
  end
72
79
 
73
80
  describe "every accessible has(1) association with :allow_destroy => false", :shared => true do
@@ -76,9 +83,17 @@ describe "every accessible has(1) association with :allow_destroy => false", :sh
76
83
  @person.save
77
84
  profile = Profile.create(:person_id => @person.id, :nick => 'snusnu')
78
85
  @person.reload
79
-
86
+
87
+ Person.all.size.should == 1
88
+ Profile.all.size.should == 1
89
+
80
90
  @person.profile_attributes = { :id => profile.id, :_delete => true }
91
+
92
+ Person.all.size.should == 1
93
+ Profile.all.size.should == 1
94
+
81
95
  @person.save
96
+
82
97
  Person.all.size.should == 1
83
98
  Profile.all.size.should == 1
84
99
  end
@@ -90,10 +105,16 @@ describe "every accessible has(1) association with :allow_destroy => true", :sha
90
105
  it "should allow to delete an existing profile via Person#profile_attributes" do
91
106
  @person.save
92
107
  profile = Profile.create(:person_id => @person.id, :nick => 'snusnu')
93
-
94
108
  @person.profile = profile
109
+
110
+ Person.all.size.should == 1
111
+ Profile.all.size.should == 1
112
+
95
113
  @person.profile_attributes = { :id => profile.id, :_delete => true }
96
114
 
115
+ Person.all.size.should == 1
116
+ Profile.all.size.should == 1
117
+
97
118
  @person.save
98
119
 
99
120
  Person.all.size.should == 1
@@ -14,27 +14,6 @@ describe "every accessible has(n) association", :shared => true do
14
14
  Task.first.name.should == 'write more specs'
15
15
  end
16
16
 
17
- it "should perform atomic commits" do
18
- Project.all.size.should == 0
19
- Task.all.size.should == 0
20
-
21
- # self is invalid
22
- @project.name = nil # will fail because of validations
23
- @project.tasks_attributes = { 'new_1' => { :name => 'write specs' } }
24
- @project.save
25
-
26
- Project.all.size.should == 0
27
- Task.all.size.should == 0
28
-
29
- # related resource is invalid
30
- @project.name = 'dm-accepts_nested_attributes'
31
- @project.tasks_attributes = { 'new_1' => { :name => nil } } # will fail because of validations
32
- @project.save
33
-
34
- Project.all.size.should == 0
35
- Task.all.size.should == 0
36
- end
37
-
38
17
  it "should return the attributes written to Project#task_attributes from the Project#task_attributes reader" do
39
18
  @project.tasks_attributes.should be_nil
40
19
  @project.tasks_attributes = { 'new_1' => { :name => 'write specs' } }
@@ -67,6 +46,10 @@ describe "every accessible has(n) association with no reject_if proc", :shared =
67
46
  Task.all.size.should == 0
68
47
 
69
48
  @project.tasks_attributes = { 'new_1' => { :name => 'write specs' } }
49
+
50
+ Project.all.size.should == 1
51
+ Task.all.size.should == 0
52
+
70
53
  @project.save.should be_true
71
54
 
72
55
  Project.all.size.should == 1
@@ -74,6 +57,27 @@ describe "every accessible has(n) association with no reject_if proc", :shared =
74
57
  Task.first.name.should == 'write specs'
75
58
  end
76
59
 
60
+ it "should perform atomic commits" do
61
+ Project.all.size.should == 0
62
+ Task.all.size.should == 0
63
+
64
+ # self is invalid
65
+ @project.name = nil # will fail because of validations
66
+ @project.tasks_attributes = { 'new_1' => { :name => 'write specs' } }
67
+ @project.save
68
+
69
+ Project.all.size.should == 0
70
+ Task.all.size.should == 0
71
+
72
+ # related resource is invalid
73
+ @project.name = 'dm-accepts_nested_attributes'
74
+ @project.tasks_attributes = { 'new_1' => { :name => nil } } # will fail because of validations
75
+ @project.save
76
+
77
+ Project.all.size.should == 0
78
+ Task.all.size.should == 0
79
+ end
80
+
77
81
  end
78
82
 
79
83
  describe "every accessible has(n) association with :allow_destroy => false", :shared => true do
@@ -99,14 +103,18 @@ describe "every accessible has(n) association with :allow_destroy => true", :sha
99
103
  it "should allow to delete an existing task via Profile#tasks_attributes" do
100
104
  @project.save
101
105
  task = Task.create(:project => @project, :name => 'write specs')
106
+ @project.tasks.reload
102
107
 
103
108
  Project.all.size.should == 1
104
109
  Task.all.size.should == 1
105
-
106
- @project.tasks << task
110
+
107
111
  @project.tasks_attributes = { '1' => { :id => task.id, :_delete => true } }
112
+
113
+ Project.all.size.should == 1
114
+ Task.all.size.should == 1
115
+
108
116
  @project.save
109
-
117
+
110
118
  Project.all.size.should == 1
111
119
  Task.all.size.should == 0
112
120
  end
@@ -23,25 +23,6 @@ describe "every accessible has(n, :through) association", :shared => true do
23
23
  Project.first.name.should == 'still dm-accepts_nested_attributes'
24
24
  end
25
25
 
26
- it "should perform atomic commits" do
27
-
28
- @person.projects_attributes = { 'new_1' => { :name => nil } } # should fail because of validations
29
- @person.save
30
-
31
- Person.all.size.should == 0 # TODO think more if this should be '1'
32
- ProjectMembership.all.size.should == 0
33
- Project.all.size.should == 0
34
-
35
- @person.name = nil # should fail because of validations
36
- @person.projects_attributes = { 'new_1' => { :name => nil } }
37
- @person.save
38
-
39
- Person.all.size.should == 0
40
- ProjectMembership.all.size.should == 0
41
- Project.all.size.should == 0
42
-
43
- end
44
-
45
26
  it "should return the attributes written to Person#projects_attributes from the Person#projects_attributes reader" do
46
27
  @person.projects_attributes.should be_nil
47
28
  @person.projects_attributes = { 'new_1' => { :name => 'write specs' } }
@@ -85,6 +66,11 @@ describe "every accessible has(n, :through) association with no reject_if proc",
85
66
  Project.all.size.should == 0
86
67
 
87
68
  @person.projects_attributes = { 'new_1' => { :name => 'dm-accepts_nested_attributes' } }
69
+
70
+ Person.all.size.should == 1
71
+ ProjectMembership.all.size.should == 0
72
+ Project.all.size.should == 0
73
+
88
74
  @person.save
89
75
 
90
76
  Person.all.size.should == 1
@@ -94,6 +80,25 @@ describe "every accessible has(n, :through) association with no reject_if proc",
94
80
  Project.first.name.should == 'dm-accepts_nested_attributes'
95
81
  end
96
82
 
83
+ it "should perform atomic commits" do
84
+
85
+ @person.projects_attributes = { 'new_1' => { :name => nil } } # should fail because of validations
86
+ @person.save
87
+
88
+ Person.all.size.should == 0 # TODO think more if this should be '1'
89
+ ProjectMembership.all.size.should == 0
90
+ Project.all.size.should == 0
91
+
92
+ @person.name = nil # should fail because of validations
93
+ @person.projects_attributes = { 'new_1' => { :name => nil } }
94
+ @person.save
95
+
96
+ Person.all.size.should == 0
97
+ ProjectMembership.all.size.should == 0
98
+ Project.all.size.should == 0
99
+
100
+ end
101
+
97
102
  end
98
103
 
99
104
  describe "every accessible has(n, :through) association with :allow_destroy => false", :shared => true do
@@ -108,6 +113,11 @@ describe "every accessible has(n, :through) association with :allow_destroy => f
108
113
  Project.all.size.should == 1
109
114
 
110
115
  @person.projects_attributes = { '1' => { :id => project.id, :_delete => true } }
116
+
117
+ Person.all.size.should == 1
118
+ ProjectMembership.all.size.should == 1
119
+ Project.all.size.should == 1
120
+
111
121
  @person.save
112
122
 
113
123
  Person.all.size.should == 1
@@ -121,19 +131,26 @@ describe "every accessible has(n, :through) association with :allow_destroy => t
121
131
 
122
132
  it "should allow to delete an existing project via Person#projects_attributes" do
123
133
  @person.save
124
- project = Project.create(:name => 'dm-accepts_nested_attributes')
125
- project_membership = ProjectMembership.create(:person => @person, :project => project)
134
+ project_1 = Project.create(:name => 'dm-accepts_nested_attributes')
135
+ project_2 = Project.create(:name => 'dm-is-localizable')
136
+ project_membership_1 = ProjectMembership.create(:person => @person, :project => project_1)
137
+ project_membership_2 = ProjectMembership.create(:person => @person, :project => project_2)
126
138
 
127
139
  Person.all.size.should == 1
128
- ProjectMembership.all.size.should == 1
129
- Project.all.size.should == 1
130
-
131
- @person.projects_attributes = { '1' => { :id => project.id, :_delete => true } }
140
+ ProjectMembership.all.size.should == 2
141
+ Project.all.size.should == 2
142
+
143
+ @person.projects_attributes = { '1' => { :id => project_1.id, :_delete => true } }
144
+
145
+ Person.all.size.should == 1
146
+ ProjectMembership.all.size.should == 2
147
+ Project.all.size.should == 2
148
+
132
149
  @person.save
133
-
150
+
134
151
  Person.all.size.should == 1
135
- ProjectMembership.all.size.should == 0
136
- Project.all.size.should == 0
152
+ ProjectMembership.all.size.should == 1
153
+ Project.all.size.should == 1
137
154
  end
138
155
 
139
156
  end