mongoid 4.0.0.alpha2 → 4.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +55 -0
  3. data/README.md +3 -3
  4. data/lib/config/locales/en.yml +13 -0
  5. data/lib/mongoid.rb +3 -1
  6. data/lib/mongoid/atomic.rb +1 -1
  7. data/lib/mongoid/atomic/paths/embedded/many.rb +1 -1
  8. data/lib/mongoid/atomic/paths/embedded/one.rb +1 -1
  9. data/lib/mongoid/attributes.rb +23 -1
  10. data/lib/mongoid/attributes/processing.rb +1 -1
  11. data/lib/mongoid/composable.rb +3 -2
  12. data/lib/mongoid/contextual/command.rb +0 -26
  13. data/lib/mongoid/contextual/geo_near.rb +1 -1
  14. data/lib/mongoid/contextual/mongo.rb +6 -29
  15. data/lib/mongoid/contextual/text_search.rb +3 -5
  16. data/lib/mongoid/criteria.rb +1 -1
  17. data/lib/mongoid/criteria/modifiable.rb +27 -7
  18. data/lib/mongoid/criteria/permission.rb +70 -0
  19. data/lib/mongoid/document.rb +5 -6
  20. data/lib/mongoid/errors.rb +2 -0
  21. data/lib/mongoid/errors/document_not_destroyed.rb +25 -0
  22. data/lib/mongoid/errors/readonly_document.rb +24 -0
  23. data/lib/mongoid/extensions/boolean.rb +1 -0
  24. data/lib/mongoid/extensions/hash.rb +1 -1
  25. data/lib/mongoid/factory.rb +5 -3
  26. data/lib/mongoid/fields.rb +32 -0
  27. data/lib/mongoid/fields/localized.rb +1 -1
  28. data/lib/mongoid/fields/standard.rb +1 -1
  29. data/lib/mongoid/findable.rb +1 -0
  30. data/lib/mongoid/interceptable.rb +11 -6
  31. data/lib/mongoid/log_subscriber.rb +34 -1
  32. data/lib/mongoid/persistable/deletable.rb +1 -0
  33. data/lib/mongoid/persistable/destroyable.rb +7 -2
  34. data/lib/mongoid/persistable/updatable.rb +27 -26
  35. data/lib/mongoid/query_cache.rb +246 -0
  36. data/lib/mongoid/railties/database.rake +4 -26
  37. data/lib/mongoid/relations.rb +8 -22
  38. data/lib/mongoid/relations/accessors.rb +0 -3
  39. data/lib/mongoid/relations/binding.rb +1 -1
  40. data/lib/mongoid/relations/bindings/embedded/in.rb +1 -1
  41. data/lib/mongoid/relations/eager.rb +5 -6
  42. data/lib/mongoid/relations/eager/base.rb +97 -5
  43. data/lib/mongoid/relations/eager/belongs_to.rb +1 -0
  44. data/lib/mongoid/relations/eager/has_and_belongs_to_many.rb +16 -9
  45. data/lib/mongoid/relations/eager/has_many.rb +1 -0
  46. data/lib/mongoid/relations/eager/has_one.rb +1 -0
  47. data/lib/mongoid/relations/embedded/batchable.rb +1 -1
  48. data/lib/mongoid/relations/embedded/in.rb +4 -4
  49. data/lib/mongoid/relations/embedded/many.rb +7 -5
  50. data/lib/mongoid/relations/embedded/one.rb +1 -1
  51. data/lib/mongoid/relations/macros.rb +1 -0
  52. data/lib/mongoid/relations/marshalable.rb +3 -3
  53. data/lib/mongoid/relations/proxy.rb +12 -10
  54. data/lib/mongoid/relations/referenced/in.rb +2 -2
  55. data/lib/mongoid/relations/referenced/many.rb +9 -9
  56. data/lib/mongoid/relations/referenced/many_to_many.rb +7 -7
  57. data/lib/mongoid/relations/referenced/one.rb +4 -4
  58. data/lib/mongoid/{state.rb → stateful.rb} +13 -1
  59. data/lib/mongoid/tasks/database.rake +31 -0
  60. data/lib/mongoid/tasks/database.rb +107 -0
  61. data/lib/mongoid/threaded.rb +0 -47
  62. data/lib/mongoid/validatable/uniqueness.rb +4 -16
  63. data/lib/mongoid/version.rb +1 -1
  64. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +0 -3
  65. data/lib/rails/mongoid.rb +0 -124
  66. data/spec/app/models/edit.rb +5 -0
  67. data/spec/app/models/even.rb +7 -0
  68. data/spec/app/models/line_item.rb +1 -1
  69. data/spec/app/models/note.rb +2 -0
  70. data/spec/app/models/odd.rb +7 -0
  71. data/spec/app/models/record.rb +5 -0
  72. data/spec/app/models/wiki_page.rb +1 -1
  73. data/spec/mongoid/attributes_spec.rb +76 -1
  74. data/spec/mongoid/changeable_spec.rb +6 -2
  75. data/spec/mongoid/contextual/mongo_spec.rb +3 -1
  76. data/spec/mongoid/contextual/text_search_spec.rb +3 -1
  77. data/spec/mongoid/criteria/modifiable_spec.rb +192 -0
  78. data/spec/mongoid/criteria_spec.rb +6 -2
  79. data/spec/mongoid/errors/document_not_destroyed_spec.rb +33 -0
  80. data/spec/mongoid/errors/readonly_document_spec.rb +29 -0
  81. data/spec/mongoid/fields/localized_spec.rb +15 -0
  82. data/spec/mongoid/fields_spec.rb +88 -2
  83. data/spec/mongoid/log_subscriber_spec.rb +3 -3
  84. data/spec/mongoid/persistable/deletable_spec.rb +14 -1
  85. data/spec/mongoid/persistable/destroyable_spec.rb +45 -1
  86. data/spec/mongoid/persistable/savable_spec.rb +34 -5
  87. data/spec/mongoid/query_cache_spec.rb +197 -0
  88. data/spec/mongoid/relations/bindings/embedded/in_spec.rb +2 -2
  89. data/spec/mongoid/relations/builders/referenced/many_spec.rb +1 -1
  90. data/spec/mongoid/relations/eager/has_and_belongs_to_many_spec.rb +11 -37
  91. data/spec/mongoid/relations/eager/has_one_spec.rb +1 -1
  92. data/spec/mongoid/relations/embedded/in_spec.rb +1 -1
  93. data/spec/mongoid/relations/embedded/many_spec.rb +10 -10
  94. data/spec/mongoid/relations/embedded/one_spec.rb +10 -2
  95. data/spec/mongoid/relations/referenced/in_spec.rb +1 -1
  96. data/spec/mongoid/relations/referenced/many_spec.rb +37 -2
  97. data/spec/mongoid/relations/touchable_spec.rb +20 -0
  98. data/spec/mongoid/{state_spec.rb → stateful_spec.rb} +26 -1
  99. data/spec/mongoid/tasks/database_rake_spec.rb +285 -0
  100. data/spec/mongoid/tasks/database_spec.rb +148 -0
  101. data/spec/mongoid/validatable/uniqueness_spec.rb +7 -0
  102. data/spec/rails/mongoid_spec.rb +0 -316
  103. data/spec/spec_helper.rb +1 -0
  104. metadata +30 -8
@@ -14,6 +14,39 @@ describe Mongoid::Attributes do
14
14
  expect(account.overridden).to eq("not recommended")
15
15
  end
16
16
  end
17
+
18
+ context "when the attribute was excluded in a criteria" do
19
+
20
+ let!(:person) do
21
+ Person.create(title: "sir")
22
+ end
23
+
24
+ context "when excluding with only" do
25
+
26
+ let(:from_db) do
27
+ Person.only(:_id).first
28
+ end
29
+
30
+ it "raises an error" do
31
+ expect {
32
+ from_db.title
33
+ }.to raise_error(ActiveModel::MissingAttributeError)
34
+ end
35
+ end
36
+
37
+ context "when excluding with without" do
38
+
39
+ let(:from_db) do
40
+ Person.without(:title).first
41
+ end
42
+
43
+ it "raises an error" do
44
+ expect {
45
+ from_db.title
46
+ }.to raise_error(ActiveModel::MissingAttributeError)
47
+ end
48
+ end
49
+ end
17
50
  end
18
51
 
19
52
  describe "#[]" do
@@ -70,6 +103,35 @@ describe Mongoid::Attributes do
70
103
  Person.create(title: "sir")
71
104
  end
72
105
 
106
+ context "when the attribute was excluded in a criteria" do
107
+
108
+ context "when excluding with only" do
109
+
110
+ let(:from_db) do
111
+ Person.only(:_id).first
112
+ end
113
+
114
+ it "raises an error" do
115
+ expect {
116
+ from_db[:title]
117
+ }.to raise_error(ActiveModel::MissingAttributeError)
118
+ end
119
+ end
120
+
121
+ context "when excluding with without" do
122
+
123
+ let(:from_db) do
124
+ Person.without(:title).first
125
+ end
126
+
127
+ it "raises an error" do
128
+ expect {
129
+ from_db[:title]
130
+ }.to raise_error(ActiveModel::MissingAttributeError)
131
+ end
132
+ end
133
+ end
134
+
73
135
  context "when the attribute does not exist" do
74
136
 
75
137
  before do
@@ -547,6 +609,19 @@ describe Mongoid::Attributes do
547
609
  expect(person.map).to eq({})
548
610
  end
549
611
  end
612
+
613
+ context "when providing tainted parameters" do
614
+
615
+ let(:params) do
616
+ ActionController::Parameters.new(title: "sir")
617
+ end
618
+
619
+ it "raises an error" do
620
+ expect {
621
+ Person.new(params)
622
+ }.to raise_error(ActiveModel::ForbiddenAttributesError)
623
+ end
624
+ end
550
625
  end
551
626
 
552
627
  context "updating when attributes already exist" do
@@ -637,6 +712,7 @@ describe Mongoid::Attributes do
637
712
  end
638
713
 
639
714
  describe "#read_attribute_before_type_cast" do
715
+
640
716
  let(:person) do
641
717
  Person.create
642
718
  end
@@ -657,7 +733,6 @@ describe Mongoid::Attributes do
657
733
  end
658
734
  end
659
735
 
660
-
661
736
  describe "#attribute_present?" do
662
737
 
663
738
  context "when document is a new record" do
@@ -1424,8 +1424,10 @@ describe Mongoid::Changeable do
1424
1424
  end
1425
1425
 
1426
1426
  after do
1427
- Acolyte._save_callbacks.reject! do |callback|
1427
+ Acolyte._save_callbacks.select do |callback|
1428
1428
  callback.kind == :after
1429
+ end.each do |callback|
1430
+ Acolyte._save_callbacks.delete(callback)
1429
1431
  end
1430
1432
  end
1431
1433
 
@@ -1448,8 +1450,10 @@ describe Mongoid::Changeable do
1448
1450
  end
1449
1451
 
1450
1452
  after do
1451
- Acolyte._save_callbacks.reject! do |callback|
1453
+ Acolyte._save_callbacks.select do |callback|
1452
1454
  callback.kind == :after
1455
+ end.each do |callback|
1456
+ Acolyte._save_callbacks.delete(callback)
1453
1457
  end
1454
1458
  end
1455
1459
 
@@ -1548,7 +1548,9 @@ describe Mongoid::Contextual::Mongo do
1548
1548
  end
1549
1549
 
1550
1550
  it "limits the fields to the projection" do
1551
- expect(documents.first.origin).to be_nil
1551
+ expect {
1552
+ documents.first.origin
1553
+ }.to raise_error(ActiveModel::MissingAttributeError)
1552
1554
  end
1553
1555
  end
1554
1556
 
@@ -37,7 +37,9 @@ describe Mongoid::Contextual::TextSearch do
37
37
  end
38
38
 
39
39
  it "limits the fields to the projection" do
40
- expect(documents.first.origin).to be_nil
40
+ expect {
41
+ documents.first.origin
42
+ }.to raise_error(ActiveModel::MissingAttributeError)
41
43
  end
42
44
  end
43
45
 
@@ -298,6 +298,157 @@ describe Mongoid::Criteria::Modifiable do
298
298
  end
299
299
  end
300
300
 
301
+ describe ".find_or_create_by!" do
302
+
303
+ context "when the document is found" do
304
+
305
+ context "when providing an attribute" do
306
+
307
+ let!(:person) do
308
+ Person.create(title: "Senior")
309
+ end
310
+
311
+ it "returns the document" do
312
+ expect(Person.find_or_create_by!(title: "Senior")).to eq(person)
313
+ end
314
+ end
315
+
316
+ context "when providing a document" do
317
+
318
+ context "with an owner with a BSON identity type" do
319
+
320
+ let!(:person) do
321
+ Person.create
322
+ end
323
+
324
+ let!(:game) do
325
+ Game.create(person: person)
326
+ end
327
+
328
+ context "when providing the object directly" do
329
+
330
+ let(:from_db) do
331
+ Game.find_or_create_by!(person: person)
332
+ end
333
+
334
+ it "returns the document" do
335
+ expect(from_db).to eq(game)
336
+ end
337
+ end
338
+
339
+ context "when providing the proxy relation" do
340
+
341
+ let(:from_db) do
342
+ Game.find_or_create_by!(person: game.person)
343
+ end
344
+
345
+ it "returns the document" do
346
+ expect(from_db).to eq(game)
347
+ end
348
+ end
349
+ end
350
+
351
+ context "with an owner with an Integer identity type" do
352
+
353
+ let!(:jar) do
354
+ Jar.create
355
+ end
356
+
357
+ let!(:cookie) do
358
+ Cookie.create(jar: jar)
359
+ end
360
+
361
+ let(:from_db) do
362
+ Cookie.find_or_create_by!(jar: jar)
363
+ end
364
+
365
+ it "returns the document" do
366
+ expect(from_db).to eq(cookie)
367
+ end
368
+ end
369
+ end
370
+ end
371
+
372
+ context "when the document is not found" do
373
+
374
+ context "when providing a document" do
375
+
376
+ let!(:person) do
377
+ Person.create
378
+ end
379
+
380
+ let!(:game) do
381
+ Game.create
382
+ end
383
+
384
+ let(:from_db) do
385
+ Game.find_or_create_by!(person: person)
386
+ end
387
+
388
+ it "returns the new document" do
389
+ expect(from_db.person).to eq(person)
390
+ end
391
+
392
+ it "does not return an existing false document" do
393
+ expect(from_db).to_not eq(game)
394
+ end
395
+ end
396
+
397
+ context "when not providing a block" do
398
+
399
+ let!(:person) do
400
+ Person.find_or_create_by!(title: "Senorita")
401
+ end
402
+
403
+ it "creates a persisted document" do
404
+ expect(person).to be_persisted
405
+ end
406
+
407
+ it "sets the attributes" do
408
+ expect(person.title).to eq("Senorita")
409
+ end
410
+ end
411
+
412
+ context "when validation fails" do
413
+
414
+ before do
415
+ Person.validates_presence_of(:title)
416
+ end
417
+
418
+ after do
419
+ Person.reset_callbacks(:validate)
420
+ end
421
+
422
+ it "raises an exception" do
423
+ expect {
424
+ Person.find_or_create_by!(ssn: "test")
425
+ }.to raise_error(Mongoid::Errors::Validations)
426
+ end
427
+ end
428
+
429
+ context "when providing a block" do
430
+
431
+ let!(:person) do
432
+ Person.find_or_create_by!(title: "Senorita") do |person|
433
+ person.pets = true
434
+ end
435
+ end
436
+
437
+ it "creates a persisted document" do
438
+ expect(person).to be_persisted
439
+ end
440
+
441
+ it "sets the attributes" do
442
+ expect(person.title).to eq("Senorita")
443
+ end
444
+
445
+ it "calls the block" do
446
+ expect(person.pets).to be true
447
+ end
448
+ end
449
+ end
450
+ end
451
+
301
452
  describe ".find_or_initialize_by" do
302
453
 
303
454
  context "when the document is found" do
@@ -404,6 +555,25 @@ describe Mongoid::Criteria::Modifiable do
404
555
  end
405
556
  end
406
557
 
558
+ context "when the criteria is on an embedded relation" do
559
+
560
+ let!(:band) do
561
+ Band.create(name: "Placebo")
562
+ end
563
+
564
+ let(:document) do
565
+ band.notes.permanent.first_or_create(text: "test")
566
+ end
567
+
568
+ it "returns a new document" do
569
+ expect(document.text).to eq("test")
570
+ end
571
+
572
+ it "returns a persisted document" do
573
+ expect(document).to be_persisted
574
+ end
575
+ end
576
+
407
577
  context "when a block is provided" do
408
578
 
409
579
  let(:document) do
@@ -1059,5 +1229,27 @@ describe Mongoid::Criteria::Modifiable do
1059
1229
  end
1060
1230
  end
1061
1231
  end
1232
+
1233
+ context "when update document structure" do
1234
+
1235
+ before do
1236
+ person = Person.new(username: "user_title", score: 25)
1237
+ person.save
1238
+ end
1239
+
1240
+ let(:from_db) do
1241
+ Person.last
1242
+ end
1243
+
1244
+ it "rename document string field" do
1245
+ Person.where(username: "user_title").update_all("$rename" => { username: "title" })
1246
+ expect(from_db.title).to eq("user_title")
1247
+ end
1248
+
1249
+ it "rename document integer field" do
1250
+ Person.where(score: 25).update_all("$rename" => { score: "age" })
1251
+ expect(from_db.age).to eq( 25 )
1252
+ end
1253
+ end
1062
1254
  end
1063
1255
  end
@@ -2611,7 +2611,9 @@ describe Mongoid::Criteria do
2611
2611
  end
2612
2612
 
2613
2613
  it "limits the returned fields" do
2614
- expect(criteria.first.name).to be_nil
2614
+ expect {
2615
+ criteria.first.name
2616
+ }.to raise_error(ActiveModel::MissingAttributeError)
2615
2617
  end
2616
2618
 
2617
2619
  it "does not add _type to the fields" do
@@ -2630,7 +2632,9 @@ describe Mongoid::Criteria do
2630
2632
  end
2631
2633
 
2632
2634
  it "excludes the non included fields" do
2633
- expect(criteria.first.active).to be_nil
2635
+ expect {
2636
+ criteria.first.active
2637
+ }.to raise_error(ActiveModel::MissingAttributeError)
2634
2638
  end
2635
2639
 
2636
2640
  it "does not add _type to the fields" do
@@ -0,0 +1,33 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Errors::DocumentNotDestroyed do
4
+
5
+ describe "#message" do
6
+
7
+ let(:post) do
8
+ Post.new
9
+ end
10
+
11
+ let(:error) do
12
+ described_class.new(post.id, Post)
13
+ end
14
+
15
+ it "contains the problem in the message" do
16
+ expect(error.message).to include(
17
+ "Post with id #{post.id.inspect} was not destroyed"
18
+ )
19
+ end
20
+
21
+ it "contains the summary in the message" do
22
+ expect(error.message).to include(
23
+ "When calling Post#destroy! and a callback halts the destroy callback"
24
+ )
25
+ end
26
+
27
+ it "contains the resolution in the message" do
28
+ expect(error.message).to include(
29
+ "Check the before/after destroy callbacks to ensure"
30
+ )
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,29 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Errors::ReadonlyDocument do
4
+
5
+ describe "#message" do
6
+
7
+ let(:error) do
8
+ described_class.new(Band)
9
+ end
10
+
11
+ it "contains the problem in the message" do
12
+ expect(error.message).to include(
13
+ "Attempted to persist the readonly document 'Band'."
14
+ )
15
+ end
16
+
17
+ it "contains the summary in the message" do
18
+ expect(error.message).to include(
19
+ "Documents loaded from the database using #only"
20
+ )
21
+ end
22
+
23
+ it "contains the resolution in the message" do
24
+ expect(error.message).to include(
25
+ "Don't attempt to persist documents that are flagged as readonly."
26
+ )
27
+ end
28
+ end
29
+ end