snusnu-dm-accepts_nested_attributes 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +4 -0
- data/README.textile +26 -5
- data/lib/dm-accepts_nested_attributes/nested_attributes.rb +104 -4
- data/lib/dm-accepts_nested_attributes/version.rb +1 -1
- data/spec/fixtures/photo.rb +9 -0
- data/spec/fixtures/profile.rb +1 -1
- data/spec/fixtures/project_membership.rb +2 -2
- data/spec/fixtures/tag.rb +12 -0
- data/spec/fixtures/tagging.rb +10 -0
- data/spec/fixtures/task.rb +1 -1
- data/spec/integration/belongs_to_spec.rb +16 -4
- data/spec/integration/has_1_spec.rb +14 -1
- data/spec/integration/has_n_spec.rb +14 -1
- data/spec/integration/has_n_through_renamed_spec.rb +214 -0
- data/spec/integration/has_n_through_spec.rb +15 -1
- data/spec/shared/rspec_tmbundle_support.rb +1 -1
- data/spec/spec_helper.rb +8 -10
- data/spec/unit/accepts_nested_attributes_for_spec.rb +34 -2
- metadata +6 -2
data/Manifest.txt
CHANGED
@@ -10,13 +10,17 @@ lib/dm-accepts_nested_attributes/associations.rb
|
|
10
10
|
lib/dm-accepts_nested_attributes/nested_attributes.rb
|
11
11
|
lib/dm-accepts_nested_attributes/version.rb
|
12
12
|
spec/fixtures/person.rb
|
13
|
+
spec/fixtures/photo.rb
|
13
14
|
spec/fixtures/profile.rb
|
14
15
|
spec/fixtures/project.rb
|
15
16
|
spec/fixtures/project_membership.rb
|
17
|
+
spec/fixtures/tag.rb
|
18
|
+
spec/fixtures/tagging.rb
|
16
19
|
spec/fixtures/task.rb
|
17
20
|
spec/integration/belongs_to_spec.rb
|
18
21
|
spec/integration/has_1_spec.rb
|
19
22
|
spec/integration/has_n_spec.rb
|
23
|
+
spec/integration/has_n_through_renamed_spec.rb
|
20
24
|
spec/integration/has_n_through_spec.rb
|
21
25
|
spec/shared/rspec_tmbundle_support.rb
|
22
26
|
spec/spec.opts
|
data/README.textile
CHANGED
@@ -8,6 +8,32 @@ For more information on the progress, have a look at this README and also at
|
|
8
8
|
"this article":http://sick.snusnu.info/2009/04/08/dm-accepts_nested_attributes/ on my blog, where I will try to comment on the
|
9
9
|
development (problems).
|
10
10
|
|
11
|
+
h2. Current limitations
|
12
|
+
|
13
|
+
Interaction with @dm-validations@ is actually possible but not very well specced atm. I added @not null@
|
14
|
+
constraints to all spec fixtures for now, but no other custom validations. All specs still pass. However,
|
15
|
+
as long as I'm not decided on where to put the specs for interaction with @dm-validations@ (most probably
|
16
|
+
inside @dm-validations@ would be the right place for these), I won't write many more specs for these scenarios,
|
17
|
+
since it's very hard to decide where to stop, once I start writing some.
|
18
|
+
|
19
|
+
Currently, the creation of the record together with all its join models, is not handled inside a transaction.
|
20
|
+
This must definitely change! As soon as I find out why my initial experiments with transactions consistently
|
21
|
+
yielded _no such table errors_ while migrating the specsuite (see "this pastie":http://pastie.org/446060), I
|
22
|
+
will do my best to add this feature.
|
23
|
+
|
24
|
+
h2. TODO
|
25
|
+
|
26
|
+
* use transactions
|
27
|
+
* update README to include more complete usecases
|
28
|
+
* specs for custom validations (dm-validations in general)
|
29
|
+
* specs for adding errors to the parent objects
|
30
|
+
* reorganize specs and fix bugs
|
31
|
+
* Adapt to datamapper/next
|
32
|
+
|
33
|
+
h2. Implementation details
|
34
|
+
|
35
|
+
This section mainly serves as a place for me to take notes during development.
|
36
|
+
|
11
37
|
h3. Why isn't this implemented as options on association declarations?
|
12
38
|
|
13
39
|
* I somehow like the declarative style of @accepts_nested_attributes_for@ better. it jumps out immediately.
|
@@ -243,8 +269,3 @@ DataMapper::NestedAttributes Person.has(n, :projects, :through => :project_membe
|
|
243
269
|
- should not allow to delete an existing project via Person#projects_attributes
|
244
270
|
</code>
|
245
271
|
</pre>
|
246
|
-
|
247
|
-
h2. TODO
|
248
|
-
|
249
|
-
* add more specs and fix bugs
|
250
|
-
* Adapt to datamapper/next
|
@@ -9,9 +9,14 @@ module DataMapper
|
|
9
9
|
|
10
10
|
module ClassMethods
|
11
11
|
|
12
|
-
# Defines an attributes writer for the specified association(s).
|
13
|
-
# are using <tt>attr_protected</tt> or <tt>attr_accessible</tt>,
|
14
|
-
# will need to add the attribute writer to the allowed list.
|
12
|
+
# Defines an attributes reader and writer for the specified association(s).
|
13
|
+
# If you are using <tt>attr_protected</tt> or <tt>attr_accessible</tt>,
|
14
|
+
# then you will need to add the attribute writer to the allowed list.
|
15
|
+
#
|
16
|
+
# After any params are passed to the attributes writer they are available
|
17
|
+
# via the attributes reader (they are stored in an instance variable of
|
18
|
+
# the same name). The attributes reader returns nil if the attributes
|
19
|
+
# writer has not been called.
|
15
20
|
#
|
16
21
|
# Supported options:
|
17
22
|
# [:allow_destroy]
|
@@ -26,8 +31,10 @@ module DataMapper
|
|
26
31
|
# do not have a <tt>_delete</tt> that evaluates to true.
|
27
32
|
#
|
28
33
|
# Examples:
|
34
|
+
# # creates avatar_attributes
|
29
35
|
# # creates avatar_attributes=
|
30
36
|
# accepts_nested_attributes_for :avatar, :reject_if => proc { |attributes| attributes['name'].blank? }
|
37
|
+
# # creates avatar_attributes and posts_attributes
|
31
38
|
# # creates avatar_attributes= and posts_attributes=
|
32
39
|
# accepts_nested_attributes_for :avatar, :posts, :allow_destroy => true
|
33
40
|
def accepts_nested_attributes_for(association_name, options = {})
|
@@ -56,7 +63,12 @@ module DataMapper
|
|
56
63
|
|
57
64
|
class_eval %{
|
58
65
|
|
66
|
+
def #{association_name}_attributes
|
67
|
+
@#{association_name}_attributes
|
68
|
+
end
|
69
|
+
|
59
70
|
def #{association_name}_attributes=(attributes)
|
71
|
+
@#{association_name}_attributes = attributes
|
60
72
|
assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes, #{options[:allow_destroy]})
|
61
73
|
end
|
62
74
|
|
@@ -141,6 +153,94 @@ module DataMapper
|
|
141
153
|
|
142
154
|
# instance methods
|
143
155
|
|
156
|
+
|
157
|
+
if ::DataMapper.const_defined?('Validate')
|
158
|
+
|
159
|
+
# NOTE:
|
160
|
+
# overwriting Resource#save like this breaks the before(:save) hook stack
|
161
|
+
# this hopefully is no problem, since the current implementation doesn't rely on
|
162
|
+
# a before(:save) hook, but rather overwrites this hook with a no-op, and adds
|
163
|
+
# the desired behavior via overwriting Resource#save directly. I'd really appreciate
|
164
|
+
# any ideas for doing this differently, though. Anyways, I'm not really sure if this
|
165
|
+
# is the right approach. I don't even know if it works with custom validations,
|
166
|
+
# or maybe breaks other things. It's also really not well specced at all atm.
|
167
|
+
# Use at your own risk :-)
|
168
|
+
|
169
|
+
def save(context = :default)
|
170
|
+
|
171
|
+
# -----------------------------------------------------------------
|
172
|
+
# ORIGINAL CODE from Resource#save
|
173
|
+
# -----------------------------------------------------------------
|
174
|
+
#
|
175
|
+
# associations_saved = false
|
176
|
+
# child_associations.each { |a| associations_saved |= a.save }
|
177
|
+
#
|
178
|
+
# saved = new_record? ? create : update
|
179
|
+
#
|
180
|
+
# if saved
|
181
|
+
# original_values.clear
|
182
|
+
# end
|
183
|
+
#
|
184
|
+
# parent_associations.each { |a| associations_saved |= a.save }
|
185
|
+
#
|
186
|
+
# # We should return true if the model (or any of its associations)
|
187
|
+
# # were saved.
|
188
|
+
# (saved | associations_saved) == true
|
189
|
+
#
|
190
|
+
# -----------------------------------------------------------------
|
191
|
+
|
192
|
+
|
193
|
+
return super if context.nil? # preserve save! behavior
|
194
|
+
|
195
|
+
associations_saved = false
|
196
|
+
|
197
|
+
child_associations.each do |a|
|
198
|
+
|
199
|
+
if a.respond_to?(:valid?)
|
200
|
+
a.errors.each { |e| self.errors.add(:general, e) } unless a.valid?(context)
|
201
|
+
else
|
202
|
+
self.errors.add(:general, "child association is missing")
|
203
|
+
end
|
204
|
+
|
205
|
+
associations_saved |= a.save
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
saved = self.valid? && (new_record? ? create : update)
|
210
|
+
|
211
|
+
if saved
|
212
|
+
original_values.clear
|
213
|
+
end
|
214
|
+
|
215
|
+
parent_associations.each do |a|
|
216
|
+
|
217
|
+
if a.respond_to?(:each)
|
218
|
+
a.each do |r|
|
219
|
+
r.errors.each { |e| self.errors.add(:general, e) } unless r.valid?(context)
|
220
|
+
end
|
221
|
+
else
|
222
|
+
a.errors.each { |e| self.errors.add(:general, e) } unless a.valid?(context)
|
223
|
+
end
|
224
|
+
|
225
|
+
associations_saved |= a.save
|
226
|
+
|
227
|
+
end
|
228
|
+
|
229
|
+
(saved | associations_saved) == true
|
230
|
+
|
231
|
+
end
|
232
|
+
|
233
|
+
# everything works the same if this method isn't overwritten with a no-op
|
234
|
+
# however, i suspect that this is the case because the registered before(:save) hook
|
235
|
+
# somehow gets lost when overwriting Resource#save here in this module.
|
236
|
+
# I'll leave it in for now, to make the purpose clear
|
237
|
+
|
238
|
+
def check_validations(context = :default)
|
239
|
+
true # no-op, validations are checked inside #save
|
240
|
+
end
|
241
|
+
|
242
|
+
end
|
243
|
+
|
144
244
|
# returns nil if no resource has been associated yet
|
145
245
|
def associated_instance_get(association_name, repository = :default)
|
146
246
|
send(self.class.association_for_name(association_name, repository).name)
|
@@ -252,7 +352,7 @@ module DataMapper
|
|
252
352
|
# do what's done in dm-core/specs/integration/association_through_spec.rb
|
253
353
|
|
254
354
|
# explicitly build the join entry and assign it to the join association
|
255
|
-
join_entry =
|
355
|
+
join_entry = self.class.associated_model_for_name(association.name).new
|
256
356
|
self.send(association.name) << join_entry
|
257
357
|
self.save
|
258
358
|
# explicitly build the child entry and assign the join entry to its join association
|
data/spec/fixtures/profile.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
class ProjectMembership
|
2
2
|
include DataMapper::Resource
|
3
3
|
property :id, Serial
|
4
|
-
property :person_id, Integer
|
5
|
-
property :project_id, Integer
|
4
|
+
property :person_id, Integer, :nullable => false
|
5
|
+
property :project_id, Integer, :nullable => false
|
6
6
|
belongs_to :person
|
7
7
|
belongs_to :project
|
8
8
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class Tag
|
2
|
+
include DataMapper::Resource
|
3
|
+
|
4
|
+
property :id, Serial
|
5
|
+
property :name, String
|
6
|
+
|
7
|
+
has n, :tagged_things, :class_name => "Tagging"
|
8
|
+
has n, :pictures, :through => :tagged_things,
|
9
|
+
:class_name => 'Photo',
|
10
|
+
:child_key => [:tag_id],
|
11
|
+
:remote_name => :photo
|
12
|
+
end
|
data/spec/fixtures/task.rb
CHANGED
@@ -7,7 +7,6 @@ describe DataMapper::NestedAttributes do
|
|
7
7
|
describe "every accessible belongs_to association with no associated parent model", :shared => true do
|
8
8
|
|
9
9
|
it "should return a new_record from get_\#{association_name}" do
|
10
|
-
@profile.person_attributes = { :name => 'Martin' }
|
11
10
|
@profile.get_person.should_not be_nil
|
12
11
|
@profile.get_person.should be_new_record
|
13
12
|
end
|
@@ -33,8 +32,8 @@ describe DataMapper::NestedAttributes do
|
|
33
32
|
it "should not allow to create a new person via Profile#person_attributes" do
|
34
33
|
@profile.person_attributes = { :name => 'Martin' }
|
35
34
|
@profile.person.should be_nil
|
36
|
-
@profile.save
|
37
|
-
Profile.all.size.should ==
|
35
|
+
@profile.save # fails because of validations (not null on belongs_to)
|
36
|
+
Profile.all.size.should == 0
|
38
37
|
Person.all.size.should == 0
|
39
38
|
end
|
40
39
|
|
@@ -112,7 +111,19 @@ describe DataMapper::NestedAttributes do
|
|
112
111
|
Profile.all.size.should == 1
|
113
112
|
Person.all.size.should == 0
|
114
113
|
end
|
114
|
+
|
115
|
+
end
|
115
116
|
|
117
|
+
describe "every accessible belongs_to association with a nested attributes reader", :shared => true do
|
118
|
+
|
119
|
+
it "should return the attributes written to Profile#person_attributes from the Profile#person_attributes reader" do
|
120
|
+
@profile.person_attributes.should be_nil
|
121
|
+
|
122
|
+
@profile.person_attributes = { :name => 'Martin' }
|
123
|
+
|
124
|
+
@profile.person_attributes.should == { :name => 'Martin' }
|
125
|
+
end
|
126
|
+
|
116
127
|
end
|
117
128
|
|
118
129
|
describe "Profile.belongs_to(:person)" do
|
@@ -127,6 +138,7 @@ describe DataMapper::NestedAttributes do
|
|
127
138
|
|
128
139
|
it_should_behave_like "every accessible belongs_to association with no reject_if proc"
|
129
140
|
it_should_behave_like "every accessible belongs_to association with :allow_destroy => false"
|
141
|
+
it_should_behave_like "every accessible belongs_to association with a nested attributes reader"
|
130
142
|
|
131
143
|
end
|
132
144
|
|
@@ -201,4 +213,4 @@ describe DataMapper::NestedAttributes do
|
|
201
213
|
|
202
214
|
end
|
203
215
|
|
204
|
-
end
|
216
|
+
end
|
@@ -101,6 +101,18 @@ describe DataMapper::NestedAttributes do
|
|
101
101
|
end
|
102
102
|
|
103
103
|
end
|
104
|
+
|
105
|
+
describe "every accessible has(1) association with a nested attributes reader", :shared => true do
|
106
|
+
|
107
|
+
it "should return the attributes written to Person#profile_attributes from the Person#profile_attributes reader" do
|
108
|
+
@person.profile_attributes.should be_nil
|
109
|
+
|
110
|
+
@person.profile_attributes = { :nick => 'snusnu' }
|
111
|
+
|
112
|
+
@person.profile_attributes.should == { :nick => 'snusnu' }
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
104
116
|
|
105
117
|
describe "Person.has(1, :profile)" do
|
106
118
|
|
@@ -114,6 +126,7 @@ describe DataMapper::NestedAttributes do
|
|
114
126
|
|
115
127
|
it_should_behave_like "every accessible has(1) association with no reject_if proc"
|
116
128
|
it_should_behave_like "every accessible has(1) association with :allow_destroy => false"
|
129
|
+
it_should_behave_like "every accessible has(1) association with a nested attributes reader"
|
117
130
|
|
118
131
|
end
|
119
132
|
|
@@ -190,4 +203,4 @@ describe DataMapper::NestedAttributes do
|
|
190
203
|
|
191
204
|
end
|
192
205
|
|
193
|
-
end
|
206
|
+
end
|
@@ -91,6 +91,18 @@ describe DataMapper::NestedAttributes do
|
|
91
91
|
end
|
92
92
|
|
93
93
|
end
|
94
|
+
|
95
|
+
describe "every accessible has(n) association with a nested attributes reader", :shared => true do
|
96
|
+
|
97
|
+
it "should return the attributes written to Project#task_attributes from the Project#task_attributes reader" do
|
98
|
+
@project.tasks_attributes.should be_nil
|
99
|
+
|
100
|
+
@project.tasks_attributes = { 'new_1' => { :name => 'write specs' } }
|
101
|
+
|
102
|
+
@project.tasks_attributes.should == { 'new_1' => { :name => 'write specs' } }
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
94
106
|
|
95
107
|
describe "Project.has(n, :tasks)" do
|
96
108
|
|
@@ -104,6 +116,7 @@ describe DataMapper::NestedAttributes do
|
|
104
116
|
|
105
117
|
it_should_behave_like "every accessible has(n) association with no reject_if proc"
|
106
118
|
it_should_behave_like "every accessible has(n) association with :allow_destroy => false"
|
119
|
+
it_should_behave_like "every accessible has(n) association with a nested attributes reader"
|
107
120
|
|
108
121
|
end
|
109
122
|
|
@@ -178,4 +191,4 @@ describe DataMapper::NestedAttributes do
|
|
178
191
|
|
179
192
|
end
|
180
193
|
|
181
|
-
end
|
194
|
+
end
|
@@ -0,0 +1,214 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
|
3
|
+
|
4
|
+
# TODO: this is overkill - really should use some more focussed unit tests instead
|
5
|
+
describe DataMapper::NestedAttributes do
|
6
|
+
|
7
|
+
describe "every accessible has(n, :through) renamed association with a valid reject_if proc", :shared => true do
|
8
|
+
|
9
|
+
it "should not allow to create a new picture via Tag#pictures_attributes" do
|
10
|
+
@tag.save
|
11
|
+
Tag.all.size.should == 1
|
12
|
+
Tagging.all.size.should == 0
|
13
|
+
Photo.all.size.should == 0
|
14
|
+
|
15
|
+
@tag.pictures_attributes = { 'new_1' => { :name => 'dm-accepts_nested_attributes' } }
|
16
|
+
@tag.pictures.should be_empty
|
17
|
+
@tag.save
|
18
|
+
|
19
|
+
Tag.all.size.should == 1
|
20
|
+
Tagging.all.size.should == 0
|
21
|
+
Photo.all.size.should == 0
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "every accessible has(n, :through) renamed association with no reject_if proc", :shared => true do
|
27
|
+
|
28
|
+
it "should allow to create a new picture via Tag#pictures_attributes" do
|
29
|
+
@tag.save
|
30
|
+
Tag.all.size.should == 1
|
31
|
+
Tagging.all.size.should == 0
|
32
|
+
Photo.all.size.should == 0
|
33
|
+
|
34
|
+
@tag.pictures_attributes = { 'new_1' => { :name => 'dm-accepts_nested_attributes' } }
|
35
|
+
@tag.pictures.should_not be_empty
|
36
|
+
@tag.pictures.first.name.should == 'dm-accepts_nested_attributes'
|
37
|
+
@tag.save
|
38
|
+
@tag.pictures.first.should == Photo.first
|
39
|
+
|
40
|
+
Tag.all.size.should == 1
|
41
|
+
Tagging.all.size.should == 1
|
42
|
+
Photo.all.size.should == 1
|
43
|
+
|
44
|
+
Photo.first.name.should == 'dm-accepts_nested_attributes'
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should allow to update an existing picture via Tag#pictures_attributes" do
|
48
|
+
@tag.save
|
49
|
+
photo = Photo.create(:name => 'dm-accepts_nested_attributes')
|
50
|
+
tagging = Tagging.create(:tag => @tag, :photo => photo)
|
51
|
+
Tag.all.size.should == 1
|
52
|
+
Photo.all.size.should == 1
|
53
|
+
Tagging.all.size.should == 1
|
54
|
+
|
55
|
+
@tag.reload
|
56
|
+
|
57
|
+
@tag.pictures_attributes = { photo.id.to_s => { :id => photo.id, :name => 'still dm-accepts_nested_attributes' } }
|
58
|
+
@tag.pictures.should_not be_empty
|
59
|
+
@tag.pictures.first.name.should == 'still dm-accepts_nested_attributes'
|
60
|
+
@tag.save
|
61
|
+
|
62
|
+
Tag.all.size.should == 1
|
63
|
+
Tagging.all.size.should == 1
|
64
|
+
Photo.all.size.should == 1
|
65
|
+
|
66
|
+
Photo.first.name.should == 'still dm-accepts_nested_attributes'
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "every accessible has(n, :through) renamed association with :allow_destroy => false", :shared => true do
|
72
|
+
|
73
|
+
it "should not allow to delete an existing picture via Tag#pictures_attributes" do
|
74
|
+
@tag.save
|
75
|
+
photo = Photo.create(:name => 'dm-accepts_nested_attributes')
|
76
|
+
tagging = Tagging.create(:tag => @tag, :photo => photo)
|
77
|
+
|
78
|
+
Tag.all.size.should == 1
|
79
|
+
Tagging.all.size.should == 1
|
80
|
+
Photo.all.size.should == 1
|
81
|
+
|
82
|
+
@tag.reload
|
83
|
+
@tag.pictures_attributes = { '1' => { :id => photo.id, :_delete => true } }
|
84
|
+
@tag.save
|
85
|
+
|
86
|
+
Tag.all.size.should == 1
|
87
|
+
Tagging.all.size.should == 1
|
88
|
+
Photo.all.size.should == 1
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "every accessible has(n, :through) renamed association with :allow_destroy => true", :shared => true do
|
94
|
+
|
95
|
+
it "should allow to delete an existing picture via Tag#pictures_attributes" do
|
96
|
+
@tag.save
|
97
|
+
photo = Photo.create(:name => 'dm-accepts_nested_attributes')
|
98
|
+
tagging = Tagging.create(:tag => @tag, :photo => photo)
|
99
|
+
|
100
|
+
Tag.all.size.should == 1
|
101
|
+
Tagging.all.size.should == 1
|
102
|
+
Photo.all.size.should == 1
|
103
|
+
|
104
|
+
@tag.reload
|
105
|
+
@tag.pictures_attributes = { '1' => { :id => photo.id, :_delete => true } }
|
106
|
+
@tag.save
|
107
|
+
|
108
|
+
Tag.all.size.should == 1
|
109
|
+
Tagging.all.size.should == 0
|
110
|
+
Photo.all.size.should == 0
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "every accessible has(n, :through) renamed association with a nested attributes reader", :shared => true do
|
116
|
+
|
117
|
+
it "should return the attributes written to Tag#pictures_attributes from the Tag#pictures_attributes reader" do
|
118
|
+
@tag.pictures_attributes.should be_nil
|
119
|
+
|
120
|
+
@tag.pictures_attributes = { 'new_1' => { :name => 'write specs' } }
|
121
|
+
|
122
|
+
@tag.pictures_attributes.should == { 'new_1' => { :name => 'write specs' } }
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
describe "Tag.has(n, :pictures, :through => :taggings) renamed" do
|
128
|
+
|
129
|
+
describe "accepts_nested_attributes_for(:pictures)" do
|
130
|
+
|
131
|
+
before(:each) do
|
132
|
+
DataMapper.auto_migrate!
|
133
|
+
Tag.accepts_nested_attributes_for :pictures
|
134
|
+
@tag = Tag.new :name => 'snusnu'
|
135
|
+
end
|
136
|
+
|
137
|
+
it_should_behave_like "every accessible has(n, :through) renamed association with no reject_if proc"
|
138
|
+
it_should_behave_like "every accessible has(n, :through) renamed association with :allow_destroy => false"
|
139
|
+
it_should_behave_like "every accessible has(n, :through) renamed association with a nested attributes reader"
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
describe "accepts_nested_attributes_for(:pictures, :allow_destroy => false)" do
|
144
|
+
|
145
|
+
before(:each) do
|
146
|
+
DataMapper.auto_migrate!
|
147
|
+
Tag.accepts_nested_attributes_for :pictures, :allow_destroy => false
|
148
|
+
@tag = Tag.new :name => 'snusnu'
|
149
|
+
end
|
150
|
+
|
151
|
+
it_should_behave_like "every accessible has(n, :through) renamed association with no reject_if proc"
|
152
|
+
it_should_behave_like "every accessible has(n, :through) renamed association with :allow_destroy => false"
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
describe "accepts_nested_attributes_for(:pictures, :allow_destroy = true)" do
|
157
|
+
|
158
|
+
before(:each) do
|
159
|
+
DataMapper.auto_migrate!
|
160
|
+
Tag.accepts_nested_attributes_for :pictures, :allow_destroy => true
|
161
|
+
@tag = Tag.new :name => 'snusnu'
|
162
|
+
end
|
163
|
+
|
164
|
+
it_should_behave_like "every accessible has(n, :through) renamed association with no reject_if proc"
|
165
|
+
it_should_behave_like "every accessible has(n, :through) renamed association with :allow_destroy => true"
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
describe "accepts_nested_attributes_for :pictures, " do
|
170
|
+
|
171
|
+
describe ":reject_if => :foo" do
|
172
|
+
|
173
|
+
before(:each) do
|
174
|
+
DataMapper.auto_migrate!
|
175
|
+
Tag.accepts_nested_attributes_for :pictures, :reject_if => :foo
|
176
|
+
@tag = Tag.new :name => 'snusnu'
|
177
|
+
end
|
178
|
+
|
179
|
+
it_should_behave_like "every accessible has(n, :through) renamed association with no reject_if proc"
|
180
|
+
it_should_behave_like "every accessible has(n, :through) renamed association with :allow_destroy => false"
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
describe ":reject_if => lambda { |attrs| true }" do
|
185
|
+
|
186
|
+
before(:each) do
|
187
|
+
DataMapper.auto_migrate!
|
188
|
+
Tag.accepts_nested_attributes_for :pictures, :reject_if => lambda { |attrs| true }
|
189
|
+
@tag = Tag.new :name => 'snusnu'
|
190
|
+
end
|
191
|
+
|
192
|
+
it_should_behave_like "every accessible has(n, :through) renamed association with a valid reject_if proc"
|
193
|
+
it_should_behave_like "every accessible has(n, :through) renamed association with :allow_destroy => false"
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
describe ":reject_if => lambda { |attrs| false }" do
|
198
|
+
|
199
|
+
before(:each) do
|
200
|
+
DataMapper.auto_migrate!
|
201
|
+
Tag.accepts_nested_attributes_for :pictures, :reject_if => lambda { |attrs| false }
|
202
|
+
@tag = Tag.new :name => 'snusnu'
|
203
|
+
end
|
204
|
+
|
205
|
+
it_should_behave_like "every accessible has(n, :through) renamed association with no reject_if proc"
|
206
|
+
it_should_behave_like "every accessible has(n, :through) renamed association with :allow_destroy => false"
|
207
|
+
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|
@@ -110,6 +110,18 @@ describe DataMapper::NestedAttributes do
|
|
110
110
|
end
|
111
111
|
|
112
112
|
end
|
113
|
+
|
114
|
+
describe "every accessible has(n, :through) association with a nested attributes reader", :shared => true do
|
115
|
+
|
116
|
+
it "should return the attributes written to Person#projects_attributes from the Person#projects_attributes reader" do
|
117
|
+
@person.projects_attributes.should be_nil
|
118
|
+
|
119
|
+
@person.projects_attributes = { 'new_1' => { :name => 'write specs' } }
|
120
|
+
|
121
|
+
@person.projects_attributes.should == { 'new_1' => { :name => 'write specs' } }
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
113
125
|
|
114
126
|
describe "Person.has(n, :projects, :through => :project_memberships)" do
|
115
127
|
|
@@ -123,6 +135,7 @@ describe DataMapper::NestedAttributes do
|
|
123
135
|
|
124
136
|
it_should_behave_like "every accessible has(n, :through) association with no reject_if proc"
|
125
137
|
it_should_behave_like "every accessible has(n, :through) association with :allow_destroy => false"
|
138
|
+
it_should_behave_like "every accessible has(n, :through) association with a nested attributes reader"
|
126
139
|
|
127
140
|
end
|
128
141
|
|
@@ -197,4 +210,5 @@ describe DataMapper::NestedAttributes do
|
|
197
210
|
|
198
211
|
end
|
199
212
|
|
200
|
-
end
|
213
|
+
end
|
214
|
+
|
data/spec/spec_helper.rb
CHANGED
@@ -13,8 +13,8 @@ require 'dm-validations'
|
|
13
13
|
require Pathname(__FILE__).dirname.parent.expand_path + 'lib/dm-accepts_nested_attributes'
|
14
14
|
|
15
15
|
ENV["SQLITE3_SPEC_URI"] ||= 'sqlite3::memory:'
|
16
|
-
ENV["MYSQL_SPEC_URI"] ||= 'mysql://localhost/
|
17
|
-
ENV["POSTGRES_SPEC_URI"] ||= 'postgres://postgres@localhost/
|
16
|
+
ENV["MYSQL_SPEC_URI"] ||= 'mysql://localhost/dm-accepts_nested_attributes_test'
|
17
|
+
ENV["POSTGRES_SPEC_URI"] ||= 'postgres://postgres@localhost/dm-accepts_nested_attributes_test'
|
18
18
|
|
19
19
|
|
20
20
|
def setup_adapter(name, default_uri = nil)
|
@@ -30,13 +30,6 @@ def setup_adapter(name, default_uri = nil)
|
|
30
30
|
false
|
31
31
|
end
|
32
32
|
end
|
33
|
-
|
34
|
-
ENV['ADAPTER'] ||= 'sqlite3'
|
35
|
-
|
36
|
-
|
37
|
-
setup_adapter(:default)
|
38
|
-
Dir[Pathname(__FILE__).dirname.to_s + "/fixtures/**/*.rb"].each { |rb| require(rb) }
|
39
|
-
|
40
33
|
|
41
34
|
# -----------------------------------------------
|
42
35
|
# support for nice html output in rspec tmbundle
|
@@ -50,9 +43,14 @@ if USE_TEXTMATE_RSPEC_BUNDLE
|
|
50
43
|
|
51
44
|
# use the tmbundle logger
|
52
45
|
RSpecTmBundleHelpers::TextmateRspecLogger.new(STDOUT, :off)
|
46
|
+
|
53
47
|
|
54
48
|
class Object
|
55
49
|
include RSpecTmBundleHelpers
|
56
50
|
end
|
57
51
|
|
58
|
-
end
|
52
|
+
end
|
53
|
+
|
54
|
+
ENV['ADAPTER'] ||= 'sqlite3'
|
55
|
+
setup_adapter(:default)
|
56
|
+
Dir[Pathname(__FILE__).dirname.to_s + "/fixtures/**/*.rb"].each { |rb| require(rb) }
|
@@ -181,6 +181,14 @@ describe "DataMapper::Model.accepts_nested_attributes_for" do
|
|
181
181
|
@model.autosave_associations[@association].should == { :allow_destroy => false }
|
182
182
|
end
|
183
183
|
|
184
|
+
it "should create a \#{association_name}_attributes instance reader" do
|
185
|
+
p = @model.new
|
186
|
+
p.respond_to?("#{@association}_attributes").should be_false
|
187
|
+
@model.accepts_nested_attributes_for @association
|
188
|
+
p = @model.new
|
189
|
+
p.respond_to?("#{@association}_attributes").should be_true
|
190
|
+
end
|
191
|
+
|
184
192
|
it "should create a \#{association_name}_attributes instance writer" do
|
185
193
|
p = @model.new
|
186
194
|
p.respond_to?("#{@association}_attributes=").should be_false
|
@@ -209,6 +217,14 @@ describe "DataMapper::Model.accepts_nested_attributes_for" do
|
|
209
217
|
@model.autosave_associations[@association].should == { :allow_destroy => false }
|
210
218
|
end
|
211
219
|
|
220
|
+
it "should create a \#{association_name}_attributes instance reader" do
|
221
|
+
p = @model.new
|
222
|
+
p.respond_to?("#{@association}_attributes").should be_false
|
223
|
+
@model.accepts_nested_attributes_for @association, {}
|
224
|
+
p = @model.new
|
225
|
+
p.respond_to?("#{@association}_attributes").should be_true
|
226
|
+
end
|
227
|
+
|
212
228
|
it "should create a \#{association_name}_attributes instance writer" do
|
213
229
|
p = @model.new
|
214
230
|
p.respond_to?("#{@association}_attributes=").should be_false
|
@@ -231,6 +247,14 @@ describe "DataMapper::Model.accepts_nested_attributes_for" do
|
|
231
247
|
@model.autosave_associations[@association].should be_nil
|
232
248
|
end
|
233
249
|
|
250
|
+
it "should not create a \#{association_name}_attributes instance reader" do
|
251
|
+
p = @model.new
|
252
|
+
p.respond_to?("#{@association}_attributes").should be_false
|
253
|
+
lambda { @model.accepts_nested_attributes_for @association, { :foo => :bar } }.should raise_error
|
254
|
+
p = @model.new
|
255
|
+
p.respond_to?("#{@association}_attributes").should be_false
|
256
|
+
end
|
257
|
+
|
234
258
|
it "should not create a \#{association_name}_attributes instance writer" do
|
235
259
|
p = @model.new
|
236
260
|
p.respond_to?("#{@association}_attributes=").should be_false
|
@@ -277,9 +301,17 @@ describe "DataMapper::Model.accepts_nested_attributes_for" do
|
|
277
301
|
@model.reject_new_nested_attributes_proc_for(@association).should be_kind_of(Proc)
|
278
302
|
end
|
279
303
|
|
304
|
+
it "should create a \#{association_name}_attributes instance reader" do
|
305
|
+
p = @model.new
|
306
|
+
p.respond_to?("#{@association}_attributes").should be_false
|
307
|
+
@model.accepts_nested_attributes_for @association, :allow_destroy => true
|
308
|
+
p = @model.new
|
309
|
+
p.respond_to?("#{@association}_attributes=").should be_true
|
310
|
+
end
|
311
|
+
|
280
312
|
it "should create a \#{association_name}_attributes instance writer" do
|
281
313
|
p = @model.new
|
282
|
-
p.respond_to?("#{@association}_attributes
|
314
|
+
p.respond_to?("#{@association}_attributes").should be_false
|
283
315
|
@model.accepts_nested_attributes_for @association, :allow_destroy => true
|
284
316
|
p = @model.new
|
285
317
|
p.respond_to?("#{@association}_attributes=").should be_true
|
@@ -451,4 +483,4 @@ describe "DataMapper::Model.accepts_nested_attributes_for" do
|
|
451
483
|
|
452
484
|
end
|
453
485
|
|
454
|
-
end
|
486
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: snusnu-dm-accepts_nested_attributes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- "Martin Gamsj\xC3\xA4ger"
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-04-
|
12
|
+
date: 2009-04-15 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -55,13 +55,17 @@ files:
|
|
55
55
|
- lib/dm-accepts_nested_attributes/nested_attributes.rb
|
56
56
|
- lib/dm-accepts_nested_attributes/version.rb
|
57
57
|
- spec/fixtures/person.rb
|
58
|
+
- spec/fixtures/photo.rb
|
58
59
|
- spec/fixtures/profile.rb
|
59
60
|
- spec/fixtures/project.rb
|
60
61
|
- spec/fixtures/project_membership.rb
|
62
|
+
- spec/fixtures/tag.rb
|
63
|
+
- spec/fixtures/tagging.rb
|
61
64
|
- spec/fixtures/task.rb
|
62
65
|
- spec/integration/belongs_to_spec.rb
|
63
66
|
- spec/integration/has_1_spec.rb
|
64
67
|
- spec/integration/has_n_spec.rb
|
68
|
+
- spec/integration/has_n_through_renamed_spec.rb
|
65
69
|
- spec/integration/has_n_through_spec.rb
|
66
70
|
- spec/shared/rspec_tmbundle_support.rb
|
67
71
|
- spec/spec.opts
|