snusnu-dm-accepts_nested_attributes 0.0.1 → 0.0.2

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.
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). If you
13
- # are using <tt>attr_protected</tt> or <tt>attr_accessible</tt>, then you
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 = Extlib::Inflection.constantize(Extlib::Inflection.classify(association.name)).new
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
@@ -1,7 +1,7 @@
1
1
  module DataMapper
2
2
  module NestedAttributes
3
3
 
4
- VERSION = "0.0.1"
4
+ VERSION = "0.0.2"
5
5
 
6
6
  end
7
7
  end
@@ -0,0 +1,9 @@
1
+ class Photo
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, :tags, :through => :tagged_things
9
+ end
@@ -1,7 +1,7 @@
1
1
  class Profile
2
2
  include DataMapper::Resource
3
3
  property :id, Serial
4
- property :person_id, Integer
4
+ property :person_id, Integer, :nullable => false
5
5
  property :nick, String
6
6
  belongs_to :person
7
7
  end
@@ -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
@@ -0,0 +1,10 @@
1
+ class Tagging
2
+ include DataMapper::Resource
3
+
4
+ property :id, Serial
5
+ property :tag_id, Integer
6
+ property :photo_id, Integer
7
+
8
+ belongs_to :tag
9
+ belongs_to :photo
10
+ end
@@ -2,6 +2,6 @@ class Task
2
2
  include DataMapper::Resource
3
3
  property :id, Serial
4
4
  property :name, String
5
- property :project_id, Integer
5
+ property :project_id, Integer, :nullable => false
6
6
  belongs_to :project
7
7
  end
@@ -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 == 1
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
+
@@ -23,7 +23,7 @@ module RSpecTmBundleHelpers
23
23
  end
24
24
  end
25
25
 
26
- def puth(html)
26
+ def puth(html = nil)
27
27
  print "#{h(html)}<br />"
28
28
  end
29
29
 
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/dm_core_test'
17
- ENV["POSTGRES_SPEC_URI"] ||= 'postgres://postgres@localhost/dm_more_test'
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=").should be_false
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.1
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-13 00:00:00 -07:00
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