mongo_mapper 0.15.0 → 0.15.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -8
  3. data/lib/mongo_mapper.rb +2 -0
  4. data/lib/mongo_mapper/plugins/accessible.rb +1 -1
  5. data/lib/mongo_mapper/plugins/associations/base.rb +10 -2
  6. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +36 -6
  7. data/lib/mongo_mapper/plugins/associations/in_foreign_array_proxy.rb +136 -0
  8. data/lib/mongo_mapper/plugins/associations/many_association.rb +4 -2
  9. data/lib/mongo_mapper/plugins/associations/proxy.rb +5 -1
  10. data/lib/mongo_mapper/plugins/associations/single_association.rb +5 -4
  11. data/lib/mongo_mapper/plugins/identity_map.rb +3 -1
  12. data/lib/mongo_mapper/plugins/keys.rb +8 -0
  13. data/lib/mongo_mapper/plugins/keys/key.rb +13 -8
  14. data/lib/mongo_mapper/plugins/modifiers.rb +12 -4
  15. data/lib/mongo_mapper/plugins/querying/decorated_plucky_query.rb +4 -3
  16. data/lib/mongo_mapper/plugins/strong_parameters.rb +26 -0
  17. data/lib/mongo_mapper/railtie.rb +1 -0
  18. data/lib/mongo_mapper/version.rb +1 -1
  19. data/spec/examples.txt +1655 -1581
  20. data/spec/functional/accessible_spec.rb +6 -0
  21. data/spec/functional/associations/belongs_to_proxy_spec.rb +18 -1
  22. data/spec/functional/associations/in_array_proxy_spec.rb +135 -0
  23. data/spec/functional/associations/in_foreign_array_proxy_spec.rb +321 -0
  24. data/spec/functional/document_spec.rb +0 -3
  25. data/spec/functional/identity_map_spec.rb +2 -2
  26. data/spec/functional/keys_spec.rb +29 -11
  27. data/spec/functional/modifiers_spec.rb +14 -0
  28. data/spec/functional/querying_spec.rb +22 -0
  29. data/spec/functional/strong_parameters_spec.rb +49 -0
  30. data/spec/unit/associations/proxy_spec.rb +0 -4
  31. data/spec/unit/keys_spec.rb +10 -1
  32. data/spec/unit/validations_spec.rb +18 -18
  33. metadata +6 -2
@@ -91,6 +91,12 @@ describe "Accessible" do
91
91
  @doc.admin.should be_falsey
92
92
  end
93
93
 
94
+ it "should ignore inaccessible attribute on #assign_attributes" do
95
+ @doc.assign_attributes({:name => 'Ren Hoek', :admin => true})
96
+ @doc.name.should == 'Ren Hoek'
97
+ @doc.admin.should be_falsey
98
+ end
99
+
94
100
  it "should be indifferent to whether the accessible keys are strings or symbols" do
95
101
  @doc.update_attributes!("name" => 'Stimpson J. Cat', "admin" => true)
96
102
  @doc.name.should == 'Stimpson J. Cat'
@@ -51,7 +51,7 @@ describe "BelongsToProxy" do
51
51
  it "should not reload the association when replacing" do
52
52
  post = @post_class.new(:name => 'mongomapper')
53
53
  comment = @comment_class.new(:name => 'Foo!', :post => post)
54
- comment.post.proxy_target.object_id.should == post.object_id
54
+ comment.post.object_id.should == post.object_id
55
55
  end
56
56
 
57
57
  it "should properly assign the associated object when assigning the association with create" do
@@ -252,4 +252,21 @@ describe "BelongsToProxy" do
252
252
  post.reload.title.should == 'Hello, world!'
253
253
  end
254
254
  end
255
+
256
+ context "regression with reassignment" do
257
+ it "should not infinite regress (shouldn't raise SystemStackError) when assigned to twice (when the proxy isn't around)" do
258
+ post = @post_class.create!
259
+ comment = @comment_class.create!(post: post)
260
+
261
+ comment = @comment_class.find(comment.id)
262
+
263
+ post = comment.post
264
+
265
+ comment.post = post
266
+
267
+ lambda do
268
+ comment.post = post
269
+ end.should_not raise_error
270
+ end
271
+ end
255
272
  end
@@ -346,4 +346,139 @@ describe "InArrayProxy" do
346
346
  end
347
347
  end
348
348
  end
349
+
350
+ describe "ordering" do
351
+ before do
352
+ @user_class = Doc("User") do
353
+ key :list_ids, Array
354
+ end
355
+
356
+ @list_class = Doc("List") do
357
+ key :name, String, :required => true
358
+ end
359
+ end
360
+
361
+ def create_list_items
362
+ @user = @user_class.create!
363
+ @list1 = @list_class.create!(:name => "one")
364
+ @list2 = @list_class.create!(:name => "two")
365
+ @list3 = @list_class.create!(:name => "three")
366
+
367
+ @user.lists << [@list3, @list2, @list1]
368
+ @user.save!
369
+
370
+ @user.reload
371
+ end
372
+
373
+ shared_examples_for "ordering is on" do
374
+ it "should have the items ordered according to order of the ids" do
375
+ @user.lists.should == [@list3, @list2, @list1]
376
+ end
377
+
378
+ it "should have the right item for #first" do
379
+ @user.lists.first.should == @list3
380
+ end
381
+
382
+ it "should have the right item for #last" do
383
+ @user.lists.last.should == @list1
384
+ end
385
+
386
+ it "does not work for pagination (but probably should)" do
387
+ @user.lists.paginate(:per_page => 100).should == [@list1, @list2, @list3]
388
+ end
389
+
390
+ it "should work with find" do
391
+ @user.lists.find(@list2.id, @list1.id).should == [@list2, @list1]
392
+ @user.lists.find(@list1.id, @list2.id).should == [@list2, @list1]
393
+ @user.lists.find(@list1.id).should == @list1
394
+ end
395
+
396
+ it "should work with find!" do
397
+ @user.lists.find!(@list2.id, @list1.id).should == [@list2, @list1]
398
+ @user.lists.find!(@list1.id, @list2.id).should == [@list2, @list1]
399
+ end
400
+
401
+ it "should only load one object with first (and no params given)" do
402
+ @list_class.should_receive(:allocate).once.and_return @list3
403
+ @user.lists.first
404
+ end
405
+
406
+ it "should only load one object with first (and params given)" do
407
+ @list_class.should_receive(:allocate).once.and_return @list3
408
+ @user.lists.first(:name => /^t/)
409
+ end
410
+
411
+ it "should only load one object with last (and no params given)" do
412
+ @list_class.should_receive(:allocate).once.and_return @list1
413
+ @user.lists.last
414
+ end
415
+
416
+ it "should only load one object with last (and params given)" do
417
+ @list_class.should_receive(:allocate).once.and_return @list3
418
+ @user.lists.last(:name => /^t/)
419
+ end
420
+
421
+ it "should return nil if first with a query matches no objects" do
422
+ @user.lists.first(:name => "non-existent").should be_nil
423
+ end
424
+
425
+ it "should return nil if last with a query matches no objects" do
426
+ @user.lists.last(:name => "non-existent").should be_nil
427
+ end
428
+
429
+ it "should work with extra query params to first and last" do
430
+ @user.lists.first(:name => /^t/).should == @list3
431
+ @user.lists.first(:name => /^o/).should == @list1
432
+
433
+ @user.lists.last(:name => /^t/).should == @list2
434
+ @user.lists.last(:name => /^o/).should == @list1
435
+ end
436
+ end
437
+
438
+ shared_examples_for "ordering is off" do
439
+ it "should include all items" do
440
+ @user.lists.length == 3
441
+ @user.lists.should include(@list1)
442
+ @user.lists.should include(@list2)
443
+ @user.lists.should include(@list3)
444
+ end
445
+
446
+ it "should return the items in the natural order" do
447
+ @user.lists.should == [@list1, @list2, @list3]
448
+ end
449
+
450
+ it "should work with find" do
451
+ @user.lists.find(@list2.id, @list1.id).should == [@list1, @list2]
452
+ @user.lists.find(@list1.id, @list2.id).should == [@list1, @list2]
453
+ @user.lists.find(@list1.id).should == @list1
454
+ end
455
+ end
456
+
457
+ describe "without a param" do
458
+ before do
459
+ @user_class.many :lists, :in => :list_ids, :class => @list_class
460
+ create_list_items
461
+ end
462
+
463
+ it_behaves_like "ordering is off"
464
+ end
465
+
466
+ describe "with ordering off" do
467
+ before do
468
+ @user_class.many :lists, :in => :list_ids, :class => @list_class, :ordered => false
469
+ create_list_items
470
+ end
471
+
472
+ it_behaves_like "ordering is off"
473
+ end
474
+
475
+ describe "with ordering on" do
476
+ before do
477
+ @user_class.many :lists, :in => :list_ids, :class => @list_class, :ordered => true
478
+ create_list_items
479
+ end
480
+
481
+ it_behaves_like "ordering is on"
482
+ end
483
+ end
349
484
  end
@@ -0,0 +1,321 @@
1
+ require 'spec_helper'
2
+
3
+ describe "InForeignArrayProxyTest" do
4
+ context "description" do
5
+ before do
6
+ class ::List
7
+ include MongoMapper::Document
8
+ key :name, String, :required => true
9
+ key :user_ids, Array
10
+ many :users, :in => :user_ids
11
+ end
12
+
13
+ class ::User
14
+ include MongoMapper::Document
15
+ key :name, String, :required => true
16
+ many :lists, :from => :user_ids, :as => :user
17
+ end
18
+ User.collection.drop
19
+ List.collection.drop
20
+ end
21
+
22
+ after do
23
+ Object.send :remove_const, 'List' if defined?(::List)
24
+ Object.send :remove_const, 'User' if defined?(::User)
25
+ end
26
+
27
+ it "should default reader to empty array" do
28
+ User.new.lists.should == []
29
+ end
30
+
31
+ it "should allow adding to association like it was an array" do
32
+ user = User.new(:name => 'John')
33
+ user.lists << List.new(:name => 'Foo1!')
34
+ user.lists.push List.new(:name => 'Foo2!')
35
+ user.lists.concat List.new(:name => 'Foo3!')
36
+ user.lists.size.should == 3
37
+ end
38
+
39
+ it "should ignore adding duplicate ids" do
40
+ user = User.create(:name => 'John')
41
+ list = List.create(:name => 'Foo')
42
+ user.lists << list
43
+ user.lists << list
44
+ user.lists << list
45
+
46
+ list.reload.user_ids.should == [user.id]
47
+ user.lists.count.should == 1
48
+ end
49
+
50
+ it "should be able to replace the association" do
51
+ user = User.new(:name => 'John')
52
+ list = List.new(:name => 'Foo')
53
+ user.lists = [list]
54
+ user.save.should == true
55
+
56
+ user.reload
57
+ list.reload
58
+ list.user_ids.should == [user.id]
59
+ user.lists.size.should == 1
60
+ user.lists[0].name.should == 'Foo'
61
+ end
62
+
63
+ context "create" do
64
+ before do
65
+ @user = User.create(:name => 'John')
66
+ @list = @user.lists.create(:name => 'Foo!')
67
+ end
68
+
69
+ it "should add id to key" do
70
+ @list.user_ids.should include(@user.id)
71
+ end
72
+
73
+ it "should persist id addition to key in database" do
74
+ @list.reload
75
+ @list.user_ids.should include(@user.id)
76
+ end
77
+
78
+ it "should add doc to association" do
79
+ @user.lists.should include(@list)
80
+ end
81
+
82
+ it "should save doc" do
83
+ @list.should_not be_new
84
+ end
85
+
86
+ it "should reset cache" do
87
+ @user.lists.size.should == 1
88
+ @user.lists.create(:name => 'Moo!')
89
+ @user.lists.size.should == 2
90
+ end
91
+ end
92
+
93
+ context "create!" do
94
+ before do
95
+ @user = User.create(:name => 'John')
96
+ @list = @user.lists.create!(:name => 'Foo!')
97
+ end
98
+
99
+ it "should add id to key" do
100
+ @list.user_ids.should include(@user.id)
101
+ end
102
+
103
+ it "should persist id addition to key in database" do
104
+ @list.reload
105
+ @list.user_ids.should include(@user.id)
106
+ end
107
+
108
+ it "should add doc to association" do
109
+ @user.lists.should include(@list)
110
+ end
111
+
112
+ it "should save doc" do
113
+ @list.should_not be_new
114
+ end
115
+
116
+ it "should raise exception if invalid" do
117
+ lambda do
118
+ @user.lists.create!
119
+ end.should raise_error(MongoMapper::DocumentNotValid)
120
+ end
121
+
122
+ it "should reset cache" do
123
+ @user.lists.size.should == 1
124
+ @user.lists.create!(:name => 'Moo!')
125
+ @user.lists.size.should == 2
126
+ end
127
+ end
128
+
129
+ context "Finding scoped to association" do
130
+ before do
131
+ @user = User.create(:name => 'John')
132
+ @user2 = User.create(:name => 'Brandon')
133
+ @list1 = @user.lists.create!(:name => 'Foo 1', :position => 1)
134
+ @list2 = @user.lists.create!(:name => 'Foo 2', :position => 2)
135
+ @list3 = @user2.lists.create!(:name => 'Foo 3', :position => 1)
136
+ end
137
+
138
+ context "all" do
139
+ it "should work" do
140
+ @user.lists.all(:order => :position.asc).should == [@list1, @list2]
141
+ end
142
+
143
+ it "should work with conditions" do
144
+ @user.lists.all(:name => 'Foo 1').should == [@list1]
145
+ end
146
+ end
147
+
148
+ context "first" do
149
+ it "should work" do
150
+ @user.lists.first(:order => 'position').should == @list1
151
+ end
152
+
153
+ it "should work with conditions" do
154
+ @user.lists.first(:position => 2).should == @list2
155
+ end
156
+ end
157
+
158
+ context "last" do
159
+ it "should work" do
160
+ @user.lists.last(:order => 'position').should == @list2
161
+ end
162
+
163
+ it "should work with conditions" do
164
+ @user.lists.last(:position => 2, :order => 'position').should == @list2
165
+ end
166
+ end
167
+
168
+ context "with one id" do
169
+ it "should work for id in association" do
170
+ @user.lists.find(@list1.id).should == @list1
171
+ end
172
+
173
+ it "should work with string ids" do
174
+ @user.lists.find(@list1.id.to_s).should == @list1
175
+ end
176
+
177
+ it "should not work for id not in association" do
178
+ @user.lists.find(@list3.id).should be_nil
179
+ end
180
+
181
+ it "should raise error when using ! and not found" do
182
+ lambda do
183
+ @user.lists.find!(@list3.id)
184
+ end.should raise_error(MongoMapper::DocumentNotFound)
185
+ end
186
+ end
187
+
188
+ context "with multiple ids" do
189
+ it "should work for ids in association" do
190
+ @user.lists.find(@list1.id, @list2.id).should == [@list1, @list2]
191
+ end
192
+
193
+ it "should not work for ids not in association" do
194
+ @user.lists.find(@list1.id, @list2.id, @list3.id).should == [@list1, @list2]
195
+ end
196
+ end
197
+
198
+ context "with #paginate" do
199
+ before do
200
+ @lists = @user.lists.paginate(:per_page => 1, :page => 1, :order => 'position')
201
+ end
202
+
203
+ it "should return total pages" do
204
+ @lists.total_pages.should == 2
205
+ end
206
+
207
+ it "should return total entries" do
208
+ @lists.total_entries.should == 2
209
+ end
210
+
211
+ it "should return the subject" do
212
+ @lists.collect(&:name).should == ['Foo 1']
213
+ end
214
+ end
215
+
216
+ context "dynamic finders" do
217
+ it "should work with single key" do
218
+ @user.lists.find_by_name('Foo 1').should == @list1
219
+ @user.lists.find_by_name!('Foo 1').should == @list1
220
+ @user.lists.find_by_name('Foo 3').should be_nil
221
+ end
222
+
223
+ it "should work with multiple keys" do
224
+ @user.lists.find_by_name_and_position('Foo 1', 1).should == @list1
225
+ @user.lists.find_by_name_and_position!('Foo 1', 1).should == @list1
226
+ @user.lists.find_by_name_and_position('Foo 3', 1).should be_nil
227
+ end
228
+
229
+ it "should raise error when using ! and not found" do
230
+ lambda do
231
+ @user.lists.find_by_name!('Foo 3')
232
+ end.should raise_error(MongoMapper::DocumentNotFound)
233
+ end
234
+
235
+ context "find_or_create_by" do
236
+ it "should not create document if found" do
237
+ lambda {
238
+ list = @user.lists.find_or_create_by_name('Foo 1')
239
+ list.should == @list1
240
+ }.should_not change { List.count }
241
+ end
242
+
243
+ it "should create document if not found" do
244
+ lambda {
245
+ list = @user.lists.find_or_create_by_name('Home')
246
+ @user.lists.should include(list)
247
+ }.should change { List.count }
248
+ end
249
+ end
250
+ end
251
+ end
252
+
253
+ context "count" do
254
+ before do
255
+ @user = User.create(:name => 'John')
256
+ @user2 = User.create(:name => 'Brandon')
257
+ @list1 = @user.lists.create!(:name => 'Foo 1')
258
+ @list2 = @user.lists.create!(:name => 'Foo 2')
259
+ @list3 = @user2.lists.create!(:name => 'Foo 3')
260
+ end
261
+
262
+ it "should return number of ids" do
263
+ @user.lists.count.should == 2
264
+ @user2.lists.count.should == 1
265
+ end
266
+
267
+ it "should return correct count when given criteria" do
268
+ @user.lists.count(:name => 'Foo 1').should == 1
269
+ @user2.lists.count(:name => 'Foo 1').should == 0
270
+ end
271
+ end
272
+
273
+ context "Removing documents" do
274
+ before do
275
+ @user = User.create(:name => 'John')
276
+ @user2 = User.create(:name => 'Brandon')
277
+ @list1 = @user.lists.create!(:name => 'Foo 1', :position => 1)
278
+ @list2 = @user.lists.create!(:name => 'Foo 2', :position => 2)
279
+ @list3 = @user2.lists.create!(:name => 'Foo 3', :position => 1)
280
+ end
281
+
282
+ context "destroy_all" do
283
+ it "should work" do
284
+ @user.lists.count.should == 2
285
+ @user.lists.destroy_all
286
+ @user.lists.count.should == 0
287
+ end
288
+
289
+ it "should work with conditions" do
290
+ @user.lists.count.should == 2
291
+ @user.lists.destroy_all(:name => 'Foo 1')
292
+ @user.lists.count.should == 1
293
+ end
294
+ end
295
+
296
+ context "delete_all" do
297
+ it "should work" do
298
+ @user.lists.count.should == 2
299
+ @user.lists.delete_all
300
+ @user.lists.count.should == 0
301
+ end
302
+
303
+ it "should work with conditions" do
304
+ @user.lists.count.should == 2
305
+ @user.lists.delete_all(:name => 'Foo 1')
306
+ @user.lists.count.should == 1
307
+ end
308
+ end
309
+
310
+ it "should work with nullify" do
311
+ @user.lists.count.should == 2
312
+
313
+ lambda {
314
+ @user.lists.nullify
315
+ }.should_not change { List.count }
316
+
317
+ @user.lists.count.should == 0
318
+ end
319
+ end
320
+ end
321
+ end