mongoid 0.9.8 → 0.9.9
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +5 -4
- data/VERSION +1 -1
- data/lib/mongoid.rb +3 -28
- data/lib/mongoid/associations.rb +63 -44
- data/lib/mongoid/associations/{relates_to_one.rb → belongs_to_related.rb} +4 -4
- data/lib/mongoid/associations/has_many.rb +26 -12
- data/lib/mongoid/associations/has_many_related.rb +100 -0
- data/lib/mongoid/associations/has_one.rb +13 -2
- data/lib/mongoid/associations/{relates_to_many.rb → has_one_related.rb} +34 -9
- data/lib/mongoid/attributes.rb +108 -8
- data/lib/mongoid/commands.rb +3 -11
- data/lib/mongoid/commands/save.rb +2 -6
- data/lib/mongoid/document.rb +6 -70
- data/lib/mongoid/errors.rb +34 -0
- data/mongoid.gemspec +14 -11
- data/spec/integration/mongoid/associations_spec.rb +19 -14
- data/spec/spec_helper.rb +6 -3
- data/spec/unit/mongoid/associations/belongs_to_related_spec.rb +112 -0
- data/spec/unit/mongoid/associations/has_many_related_spec.rb +292 -0
- data/spec/unit/mongoid/associations/has_many_spec.rb +17 -0
- data/spec/unit/mongoid/associations/has_one_related_spec.rb +130 -0
- data/spec/unit/mongoid/associations/has_one_spec.rb +53 -0
- data/spec/unit/mongoid/associations_spec.rb +36 -8
- data/spec/unit/mongoid/attributes_spec.rb +218 -0
- data/spec/unit/mongoid/commands/save_spec.rb +4 -2
- data/spec/unit/mongoid/commands_spec.rb +4 -17
- data/spec/unit/mongoid/criteria_spec.rb +0 -5
- data/spec/unit/mongoid/document_spec.rb +26 -156
- data/spec/unit/mongoid/errors_spec.rb +87 -0
- metadata +14 -11
- data/lib/mongoid/commands/quick_save.rb +0 -19
- data/spec/unit/mongoid/associations/relates_to_many_spec.rb +0 -76
- data/spec/unit/mongoid/associations/relates_to_one_spec.rb +0 -112
- data/spec/unit/mongoid/commands/quick_save_spec.rb +0 -24
@@ -209,6 +209,23 @@ describe Mongoid::Associations::HasMany do
|
|
209
209
|
|
210
210
|
end
|
211
211
|
|
212
|
+
describe "#nested_build" do
|
213
|
+
|
214
|
+
before do
|
215
|
+
@association = Mongoid::Associations::HasMany.new(
|
216
|
+
@document,
|
217
|
+
Mongoid::Associations::Options.new(:name => :addresses)
|
218
|
+
)
|
219
|
+
end
|
220
|
+
|
221
|
+
it "returns the newly built object in the association" do
|
222
|
+
@association.nested_build({ "0" => { :street => "Yet Another" } })
|
223
|
+
@association.size.should == 3
|
224
|
+
@association.last.street.should == "Yet Another"
|
225
|
+
end
|
226
|
+
|
227
|
+
end
|
228
|
+
|
212
229
|
describe "#push" do
|
213
230
|
|
214
231
|
before do
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Mongoid::Associations::HasOneRelated do
|
4
|
+
|
5
|
+
let(:document) { stub(:id => "1") }
|
6
|
+
let(:options) { Mongoid::Associations::Options.new(:name => :game) }
|
7
|
+
|
8
|
+
describe "#build" do
|
9
|
+
|
10
|
+
before do
|
11
|
+
@parent = stub(:id => "5", :class => Person)
|
12
|
+
Game.expects(:first).returns(nil)
|
13
|
+
@association = Mongoid::Associations::HasOneRelated.new(@parent, options)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "adds a new object to the association" do
|
17
|
+
@association.build(:score => 100)
|
18
|
+
@association.score.should == 100
|
19
|
+
end
|
20
|
+
|
21
|
+
it "sets the parent object id on the child" do
|
22
|
+
@association.build(:score => 100)
|
23
|
+
@association.person_id.should == @parent.id
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#create" do
|
29
|
+
|
30
|
+
before do
|
31
|
+
@parent = stub(:id => "5", :class => Person)
|
32
|
+
Game.expects(:first).returns(nil)
|
33
|
+
Mongoid::Commands::Save.expects(:execute)
|
34
|
+
@association = Mongoid::Associations::HasOneRelated.new(@parent, options)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "adds a new object to the association" do
|
38
|
+
@association.create(:score => 100)
|
39
|
+
@association.score.should == 100
|
40
|
+
end
|
41
|
+
|
42
|
+
it "sets the parent object id on the child" do
|
43
|
+
@association.create(:score => 100)
|
44
|
+
@association.person_id.should == @parent.id
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
describe ".initialize" do
|
50
|
+
|
51
|
+
before do
|
52
|
+
@person = Person.new
|
53
|
+
@game = stub
|
54
|
+
end
|
55
|
+
|
56
|
+
it "finds the association game by the parent key" do
|
57
|
+
Game.expects(:first).with(:conditions => { "person_id"=> @person.id }).returns(@game)
|
58
|
+
@person.game.should == @game
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
describe ".instantiate" do
|
64
|
+
|
65
|
+
it "delegates to new" do
|
66
|
+
Mongoid::Associations::HasOneRelated.expects(:new).with(document, options)
|
67
|
+
Mongoid::Associations::HasOneRelated.instantiate(document, options)
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "#method_missing" do
|
73
|
+
|
74
|
+
before do
|
75
|
+
@person = Person.new
|
76
|
+
@game = stub
|
77
|
+
end
|
78
|
+
|
79
|
+
it "delegates to the documet" do
|
80
|
+
Game.expects(:first).with(:conditions => { "person_id"=> @person.id }).returns(@game)
|
81
|
+
@game.expects(:strange_method)
|
82
|
+
association = Mongoid::Associations::HasOneRelated.instantiate(@person, options)
|
83
|
+
association.strange_method
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
describe ".macro" do
|
89
|
+
|
90
|
+
it "returns :has_one_related" do
|
91
|
+
Mongoid::Associations::HasOneRelated.macro.should == :has_one_related
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "#nil?" do
|
97
|
+
|
98
|
+
before do
|
99
|
+
@person = Person.new
|
100
|
+
@game = stub
|
101
|
+
Game.expects(:first).with(:conditions => { "person_id"=> @person.id }).returns(nil)
|
102
|
+
end
|
103
|
+
|
104
|
+
it "delegates to the document" do
|
105
|
+
association = Mongoid::Associations::HasOneRelated.instantiate(@person, options)
|
106
|
+
association.should be_nil
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
describe ".update" do
|
112
|
+
|
113
|
+
before do
|
114
|
+
@person = Person.new
|
115
|
+
@game = stub
|
116
|
+
end
|
117
|
+
|
118
|
+
it "sets the parent on the child association" do
|
119
|
+
@game.expects(:person=).with(@person)
|
120
|
+
Mongoid::Associations::HasOneRelated.update(@game, @person, options)
|
121
|
+
end
|
122
|
+
|
123
|
+
it "returns the child" do
|
124
|
+
@game.expects(:person=).with(@person)
|
125
|
+
Mongoid::Associations::HasOneRelated.update(@game, @person, options).should == @game
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
@@ -80,6 +80,27 @@ describe Mongoid::Associations::HasOne do
|
|
80
80
|
|
81
81
|
end
|
82
82
|
|
83
|
+
describe "#nested_build" do
|
84
|
+
|
85
|
+
context "when attributes provided" do
|
86
|
+
|
87
|
+
before do
|
88
|
+
@association = Mongoid::Associations::HasOne.new(
|
89
|
+
@document,
|
90
|
+
@attributes[:mixed_drink],
|
91
|
+
Mongoid::Associations::Options.new(:name => :mixed_drink)
|
92
|
+
)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "replaces the existing has_one" do
|
96
|
+
drink = @association.nested_build({ :name => "Sapphire and Tonic" })
|
97
|
+
drink.name.should == "Sapphire and Tonic"
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
83
104
|
describe ".instantiate" do
|
84
105
|
|
85
106
|
context "when attributes exist" do
|
@@ -129,4 +150,36 @@ describe Mongoid::Associations::HasOne do
|
|
129
150
|
|
130
151
|
end
|
131
152
|
|
153
|
+
describe "#valid?" do
|
154
|
+
|
155
|
+
context "when the document is nil" do
|
156
|
+
|
157
|
+
before do
|
158
|
+
@document = stub(:attributes => {})
|
159
|
+
@options = Mongoid::Associations::Options.new(:name => :name)
|
160
|
+
@association = Mongoid::Associations::HasOne.instantiate(@document, @options)
|
161
|
+
end
|
162
|
+
|
163
|
+
it "returns false" do
|
164
|
+
@association.valid?.should be_false
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
context "when the document is not nil" do
|
170
|
+
|
171
|
+
before do
|
172
|
+
@document = stub(:attributes => { :name => { :first_name => "Test" } }, :update => true)
|
173
|
+
@options = Mongoid::Associations::Options.new(:name => :name)
|
174
|
+
@association = Mongoid::Associations::HasOne.instantiate(@document, @options)
|
175
|
+
end
|
176
|
+
|
177
|
+
it "validates the document" do
|
178
|
+
@association.valid?.should be_true
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
|
132
185
|
end
|
@@ -97,6 +97,14 @@ describe Mongoid::Associations do
|
|
97
97
|
code.phone_number.should == phone_number
|
98
98
|
end
|
99
99
|
|
100
|
+
context "when inverse_of not supplied" do
|
101
|
+
|
102
|
+
it "raises an error" do
|
103
|
+
lambda { Person.class_eval { belongs_to :nothing } }.should raise_error
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
100
108
|
context "when navigating the graph" do
|
101
109
|
|
102
110
|
before do
|
@@ -241,20 +249,39 @@ describe Mongoid::Associations do
|
|
241
249
|
|
242
250
|
end
|
243
251
|
|
244
|
-
describe ".
|
252
|
+
describe ".belongs_to_related" do
|
253
|
+
|
254
|
+
before do
|
255
|
+
@game = Game.new
|
256
|
+
end
|
245
257
|
|
246
258
|
it "creates an id field for the relationship" do
|
247
|
-
|
259
|
+
@game.should respond_to(:person_id)
|
248
260
|
end
|
249
261
|
|
250
|
-
it "creates a getter
|
251
|
-
|
252
|
-
|
262
|
+
it "creates a getter for the parent" do
|
263
|
+
@game.should respond_to(:person)
|
264
|
+
end
|
265
|
+
|
266
|
+
end
|
267
|
+
|
268
|
+
describe ".has_one_related" do
|
269
|
+
|
270
|
+
before do
|
271
|
+
@person = Person.new
|
272
|
+
end
|
273
|
+
|
274
|
+
it "creates a getter for the relationship" do
|
275
|
+
@person.should respond_to(:game)
|
276
|
+
end
|
277
|
+
|
278
|
+
it "creates a setter for the relationship" do
|
279
|
+
@person.should respond_to(:game=)
|
253
280
|
end
|
254
281
|
|
255
282
|
end
|
256
283
|
|
257
|
-
describe ".
|
284
|
+
describe ".has_many_related" do
|
258
285
|
|
259
286
|
it "creates a getter and setter for the relationship" do
|
260
287
|
Person.new.should respond_to(:posts)
|
@@ -274,7 +301,7 @@ describe Mongoid::Associations do
|
|
274
301
|
end
|
275
302
|
|
276
303
|
it "saves each association" do
|
277
|
-
@related.expects(:
|
304
|
+
@related.expects(:save).returns(@related)
|
278
305
|
@person.update_associations(:posts)
|
279
306
|
end
|
280
307
|
|
@@ -287,6 +314,7 @@ describe Mongoid::Associations do
|
|
287
314
|
end
|
288
315
|
|
289
316
|
it "does nothing" do
|
317
|
+
Post.expects(:find).returns([])
|
290
318
|
@person.update_associations(:posts)
|
291
319
|
@person.posts.first.should be_nil
|
292
320
|
end
|
@@ -306,7 +334,7 @@ describe Mongoid::Associations do
|
|
306
334
|
end
|
307
335
|
|
308
336
|
it "saves each association" do
|
309
|
-
@related.expects(:
|
337
|
+
@related.expects(:save).returns(@related)
|
310
338
|
@person.update_association(:game)
|
311
339
|
end
|
312
340
|
|
@@ -2,6 +2,78 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe Mongoid::Attributes do
|
4
4
|
|
5
|
+
describe ".accepts_nested_attributes_for" do
|
6
|
+
|
7
|
+
before do
|
8
|
+
@person = Person.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it "adds a setter for the association attributes" do
|
12
|
+
@person.should respond_to(:addresses_attributes=)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#association_attributes=" do
|
16
|
+
|
17
|
+
context "on a has many association" do
|
18
|
+
|
19
|
+
context "when association is empty" do
|
20
|
+
|
21
|
+
before do
|
22
|
+
@attributes = {
|
23
|
+
"0" => { "street" => "Folsom", "city" => "San Francisco" }
|
24
|
+
}
|
25
|
+
@person.addresses_attributes = @attributes
|
26
|
+
end
|
27
|
+
|
28
|
+
it "adds a new document to the association" do
|
29
|
+
address = @person.addresses.first
|
30
|
+
address.street.should == "Folsom"
|
31
|
+
address.city.should == "San Francisco"
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
context "when association is not empty" do
|
37
|
+
|
38
|
+
before do
|
39
|
+
@person = Person.new
|
40
|
+
@person.addresses.build(:street => "Broadway", :city => "New York")
|
41
|
+
@attributes = {
|
42
|
+
"0" => { "street" => "Folsom", "city" => "San Francisco" }
|
43
|
+
}
|
44
|
+
@person.addresses_attributes = @attributes
|
45
|
+
end
|
46
|
+
|
47
|
+
it "updates the existing attributes on the association" do
|
48
|
+
@person.addresses.size.should == 2
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
context "on a has one association" do
|
56
|
+
|
57
|
+
before do
|
58
|
+
@person = Person.new
|
59
|
+
@attributes = {
|
60
|
+
"first_name" => "Fernando", "last_name" => "Torres"
|
61
|
+
}
|
62
|
+
@person.name_attributes = @attributes
|
63
|
+
end
|
64
|
+
|
65
|
+
it "replaces the document on the association" do
|
66
|
+
name = @person.name
|
67
|
+
name.first_name.should == "Fernando"
|
68
|
+
name.last_name.should == "Torres"
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
5
77
|
describe "#process" do
|
6
78
|
|
7
79
|
context "when supplied hash has values" do
|
@@ -94,4 +166,150 @@ describe Mongoid::Attributes do
|
|
94
166
|
|
95
167
|
end
|
96
168
|
|
169
|
+
describe "#read_attribute" do
|
170
|
+
|
171
|
+
context "when attribute does not exist" do
|
172
|
+
|
173
|
+
before do
|
174
|
+
@person = Person.new
|
175
|
+
end
|
176
|
+
|
177
|
+
it "returns the default value" do
|
178
|
+
@person.age.should == 100
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
describe "#remove_attribute" do
|
186
|
+
|
187
|
+
context "when the attribute exists" do
|
188
|
+
|
189
|
+
it "removes the attribute" do
|
190
|
+
person = Person.new(:title => "Sir")
|
191
|
+
person.remove_attribute(:title)
|
192
|
+
person.title.should be_nil
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
context "when the attribute does not exist" do
|
198
|
+
|
199
|
+
it "does nothing" do
|
200
|
+
person = Person.new
|
201
|
+
person.remove_attribute(:title)
|
202
|
+
person.title.should be_nil
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
describe "#write_attribute" do
|
210
|
+
|
211
|
+
context "when attribute does not exist" do
|
212
|
+
|
213
|
+
before do
|
214
|
+
@person = Person.new
|
215
|
+
end
|
216
|
+
|
217
|
+
it "returns the default value" do
|
218
|
+
@person.age = nil
|
219
|
+
@person.age.should == 100
|
220
|
+
end
|
221
|
+
|
222
|
+
end
|
223
|
+
|
224
|
+
context "when field has a default value" do
|
225
|
+
|
226
|
+
before do
|
227
|
+
@person = Person.new
|
228
|
+
end
|
229
|
+
|
230
|
+
it "should allow overwriting of the default value" do
|
231
|
+
@person.terms = true
|
232
|
+
@person.terms.should be_true
|
233
|
+
end
|
234
|
+
|
235
|
+
end
|
236
|
+
|
237
|
+
end
|
238
|
+
|
239
|
+
describe "#write_attributes" do
|
240
|
+
|
241
|
+
context "typecasting" do
|
242
|
+
|
243
|
+
before do
|
244
|
+
@person = Person.new
|
245
|
+
@attributes = { :age => "50" }
|
246
|
+
end
|
247
|
+
|
248
|
+
it "properly casts values" do
|
249
|
+
@person.write_attributes(@attributes)
|
250
|
+
@person.age.should == 50
|
251
|
+
end
|
252
|
+
|
253
|
+
end
|
254
|
+
|
255
|
+
context "on a parent document" do
|
256
|
+
|
257
|
+
context "when the parent has a has many through a has one" do
|
258
|
+
|
259
|
+
before do
|
260
|
+
@owner = PetOwner.new(:title => "Mr")
|
261
|
+
@pet = Pet.new(:name => "Fido")
|
262
|
+
@owner.pet = @pet
|
263
|
+
@vet_visit = VetVisit.new(:date => Date.today)
|
264
|
+
@pet.vet_visits = [@vet_visit]
|
265
|
+
end
|
266
|
+
|
267
|
+
it "does not overwrite child attributes if not in the hash" do
|
268
|
+
@owner.write_attributes({ :pet => { :name => "Bingo" } })
|
269
|
+
@owner.pet.name.should == "Bingo"
|
270
|
+
@owner.pet.vet_visits.size.should == 1
|
271
|
+
end
|
272
|
+
|
273
|
+
end
|
274
|
+
|
275
|
+
end
|
276
|
+
|
277
|
+
context "on a child document" do
|
278
|
+
|
279
|
+
context "when child is part of a has one" do
|
280
|
+
|
281
|
+
before do
|
282
|
+
@person = Person.new(:title => "Sir", :age => 30)
|
283
|
+
@name = Name.new(:first_name => "Test", :last_name => "User")
|
284
|
+
@person.name = @name
|
285
|
+
end
|
286
|
+
|
287
|
+
it "sets the child attributes on the parent" do
|
288
|
+
@name.write_attributes(:first_name => "Test2", :last_name => "User2")
|
289
|
+
@person.attributes[:name].should ==
|
290
|
+
{ "_id" => "test-user", "first_name" => "Test2", "last_name" => "User2" }
|
291
|
+
end
|
292
|
+
|
293
|
+
end
|
294
|
+
|
295
|
+
context "when child is part of a has many" do
|
296
|
+
|
297
|
+
before do
|
298
|
+
@person = Person.new(:title => "Sir")
|
299
|
+
@address = Address.new(:street => "Test")
|
300
|
+
@person.addresses << @address
|
301
|
+
end
|
302
|
+
|
303
|
+
it "updates the child attributes on the parent" do
|
304
|
+
@address.write_attributes("street" => "Test2")
|
305
|
+
@person.attributes[:addresses].should ==
|
306
|
+
[ { "_id" => "test", "street" => "Test2" } ]
|
307
|
+
end
|
308
|
+
|
309
|
+
end
|
310
|
+
|
311
|
+
end
|
312
|
+
|
313
|
+
end
|
314
|
+
|
97
315
|
end
|