mongoid 4.0.0.alpha2 → 4.0.0.beta1

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