mongo_mapper 0.15.0 → 0.15.1

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