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 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