mongoid 0.9.8 → 0.9.9
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/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
|