mongoid 9.1.1 → 9.1.2
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.
- checksums.yaml +4 -4
- data/lib/config/locales/en.yml +31 -11
- data/lib/mongoid/association/accessors.rb +18 -4
- data/lib/mongoid/association/eager_load/discriminated_inclusion.rb +10 -10
- data/lib/mongoid/association/eager_load/embedded_distributor.rb +6 -6
- data/lib/mongoid/association/eager_load/lookup_pipeline.rb +1 -1
- data/lib/mongoid/association/eager_loadable.rb +8 -1
- data/lib/mongoid/association/embedded/batchable.rb +17 -1
- data/lib/mongoid/association/nested/many.rb +1 -1
- data/lib/mongoid/association/referenced/has_and_belongs_to_many/buildable.rb +6 -0
- data/lib/mongoid/association/relatable.rb +18 -0
- data/lib/mongoid/association.rb +8 -0
- data/lib/mongoid/atomic/modifiers.rb +100 -16
- data/lib/mongoid/clients/factory.rb +2 -0
- data/lib/mongoid/config/encryption.rb +148 -17
- data/lib/mongoid/document.rb +3 -0
- data/lib/mongoid/encryptable.rb +42 -15
- data/lib/mongoid/errors/invalid_encryption_schema.rb +27 -0
- data/lib/mongoid/errors/no_encryption_schema.rb +5 -3
- data/lib/mongoid/errors.rb +1 -0
- data/lib/mongoid/fields.rb +7 -0
- data/lib/mongoid/persistable/creatable.rb +120 -14
- data/lib/mongoid/persistable.rb +15 -15
- data/lib/mongoid/persistence_context.rb +46 -4
- data/lib/mongoid/search_indexable.rb +5 -1
- data/lib/mongoid/tasks/database.rb +10 -7
- data/lib/mongoid/touchable.rb +28 -1
- data/lib/mongoid/version.rb +1 -1
- data/lib/mongoid/warnings.rb +4 -0
- data/spec/integration/associations/embedded_delayed_atomic_sets_spec.rb +216 -0
- data/spec/integration/associations/has_and_belongs_to_many_spec.rb +14 -0
- data/spec/integration/atomic/modifiers_spec.rb +283 -0
- data/spec/integration/encryption_spec.rb +149 -0
- data/spec/mongoid/association/accessors_spec.rb +35 -0
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/buildable_spec.rb +11 -0
- data/spec/mongoid/atomic/modifiers_spec.rb +347 -0
- data/spec/mongoid/attributes/nested_spec.rb +29 -0
- data/spec/mongoid/clients/factory_spec.rb +36 -0
- data/spec/mongoid/config/encryption_spec.rb +223 -0
- data/spec/mongoid/criteria/includable_spec.rb +346 -0
- data/spec/mongoid/encryptable_spec.rb +54 -0
- data/spec/mongoid/fields_spec.rb +8 -0
- data/spec/mongoid/search_indexable_spec.rb +26 -0
- data/spec/mongoid/tasks/database_spec.rb +13 -0
- data/spec/mongoid/touchable_spec.rb +217 -0
- data/spec/mongoid/touchable_spec_models.rb +37 -0
- data/spec/support/crypt/models.rb +96 -0
- data/spec/support/models/modifier_models.rb +65 -0
- metadata +5 -2
|
@@ -254,6 +254,19 @@ describe Mongoid::Tasks::Database do
|
|
|
254
254
|
described_class.create_search_indexes([ searchable_model_spy ], wait: false)
|
|
255
255
|
end
|
|
256
256
|
end
|
|
257
|
+
|
|
258
|
+
context 'when waiting for the indexes' do
|
|
259
|
+
it 'runs the wait inside collection management' do
|
|
260
|
+
managing = nil
|
|
261
|
+
allow(described_class).to receive(:wait_for_search_indexes) do
|
|
262
|
+
managing = Mongoid::Threaded.managing_collection?
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
described_class.create_search_indexes([ searchable_model_spy ], wait: true)
|
|
266
|
+
|
|
267
|
+
expect(managing).to be true
|
|
268
|
+
end
|
|
269
|
+
end
|
|
257
270
|
end
|
|
258
271
|
|
|
259
272
|
describe '.remove_search_indexes' do
|
|
@@ -1400,6 +1400,46 @@ describe Mongoid::Touchable do
|
|
|
1400
1400
|
end
|
|
1401
1401
|
end
|
|
1402
1402
|
|
|
1403
|
+
describe 'the parent chain touch paths' do
|
|
1404
|
+
context 'on a root document' do
|
|
1405
|
+
it 'contains the root updated_at path' do
|
|
1406
|
+
expect(TouchableParent.new._touchable_chain_paths).to eq(%w[updated_at])
|
|
1407
|
+
end
|
|
1408
|
+
end
|
|
1409
|
+
|
|
1410
|
+
context 'on an embedded document with a touchable parent' do
|
|
1411
|
+
let(:parent) do
|
|
1412
|
+
parent = TouchableParent.create!
|
|
1413
|
+
parent.child = TouchableChild.create!(parent: parent)
|
|
1414
|
+
parent
|
|
1415
|
+
end
|
|
1416
|
+
|
|
1417
|
+
it 'contains the paths of each node in the chain' do
|
|
1418
|
+
expect(parent.child._touchable_chain_paths)
|
|
1419
|
+
.to eq(%w[child.updated_at updated_at])
|
|
1420
|
+
end
|
|
1421
|
+
end
|
|
1422
|
+
|
|
1423
|
+
context 'with a custom touch field' do
|
|
1424
|
+
it 'contains the custom field path of the anchor document' do
|
|
1425
|
+
building = TouchableSpec::Embedded::Building.create!
|
|
1426
|
+
|
|
1427
|
+
expect(building._touchable_chain_paths(:last_used_at))
|
|
1428
|
+
.to eq(%w[updated_at last_used_at])
|
|
1429
|
+
end
|
|
1430
|
+
end
|
|
1431
|
+
|
|
1432
|
+
context 'when the models use Timestamps::Short' do
|
|
1433
|
+
it 'resolves the aliased timestamp fields' do
|
|
1434
|
+
building = TouchableSpec::Short::Building.create!
|
|
1435
|
+
building.floors.create!
|
|
1436
|
+
|
|
1437
|
+
expect(building.reload.floors.first._touchable_chain_paths)
|
|
1438
|
+
.to eq(%w[floors.0.u_at u_at])
|
|
1439
|
+
end
|
|
1440
|
+
end
|
|
1441
|
+
end
|
|
1442
|
+
|
|
1403
1443
|
describe 'touch merged with embedded insert' do
|
|
1404
1444
|
context 'when pushing an embedded document with touch: true' do
|
|
1405
1445
|
let(:building) do
|
|
@@ -1424,6 +1464,21 @@ describe Mongoid::Touchable do
|
|
|
1424
1464
|
end
|
|
1425
1465
|
end
|
|
1426
1466
|
|
|
1467
|
+
it 'sends the merged touch updates rewritten to the positional operator' do
|
|
1468
|
+
subscriber = Mrss::EventSubscriber.new
|
|
1469
|
+
Mongoid.client(:default).subscribe(Mongo::Monitoring::COMMAND, subscriber)
|
|
1470
|
+
begin
|
|
1471
|
+
floor.sofas.push(TouchableSpec::Embedded::Sofa.new)
|
|
1472
|
+
ensure
|
|
1473
|
+
Mongoid.client(:default).unsubscribe(Mongo::Monitoring::COMMAND, subscriber)
|
|
1474
|
+
end
|
|
1475
|
+
|
|
1476
|
+
command = subscriber.single_command_started_event('update').command
|
|
1477
|
+
sets = command['updates'].first['u']['$set']
|
|
1478
|
+
|
|
1479
|
+
expect(sets.keys).to contain_exactly('floors.$.updated_at', 'updated_at')
|
|
1480
|
+
end
|
|
1481
|
+
|
|
1427
1482
|
it 'updates updated_at on the parent after push' do
|
|
1428
1483
|
original_floor_updated_at = floor.updated_at
|
|
1429
1484
|
original_building_updated_at = building.updated_at
|
|
@@ -1536,5 +1591,167 @@ describe Mongoid::Touchable do
|
|
|
1536
1591
|
expect(building.updated_at).to be > original_updated_at
|
|
1537
1592
|
end
|
|
1538
1593
|
end
|
|
1594
|
+
|
|
1595
|
+
context 'when an existing child of the same array has a pending touch' do
|
|
1596
|
+
let(:building) do
|
|
1597
|
+
TouchableSpec::Embedded::Building.create!(title: 'Tower')
|
|
1598
|
+
end
|
|
1599
|
+
|
|
1600
|
+
before do
|
|
1601
|
+
floor = building.floors.create!(level: 1)
|
|
1602
|
+
# Leave a pending touch on the existing sibling so merging it into
|
|
1603
|
+
# the insert would target a path inside the pushed array.
|
|
1604
|
+
floor.updated_at = Time.now + 60
|
|
1605
|
+
end
|
|
1606
|
+
|
|
1607
|
+
it 'does not raise a conflict error when creating a sibling' do
|
|
1608
|
+
expect { building.floors.create!(level: 2) }.not_to raise_error
|
|
1609
|
+
end
|
|
1610
|
+
|
|
1611
|
+
it 'persists the new sibling' do
|
|
1612
|
+
building.floors.create!(level: 2)
|
|
1613
|
+
expect(building.reload.floors.length).to eq(2)
|
|
1614
|
+
end
|
|
1615
|
+
|
|
1616
|
+
it 'touches the parent' do
|
|
1617
|
+
building.floors.create!(level: 2)
|
|
1618
|
+
building.reload
|
|
1619
|
+
expect(building.updated_at).to be_within(5).of(Time.now)
|
|
1620
|
+
end
|
|
1621
|
+
end
|
|
1622
|
+
|
|
1623
|
+
context 'when a sibling in a parent array has a pending touch' do
|
|
1624
|
+
let(:building) do
|
|
1625
|
+
TouchableSpec::Embedded::Building.create!(title: 'Tower')
|
|
1626
|
+
end
|
|
1627
|
+
|
|
1628
|
+
let(:first_floor) do
|
|
1629
|
+
building.floors.create!(level: 1)
|
|
1630
|
+
end
|
|
1631
|
+
|
|
1632
|
+
let(:second_floor) do
|
|
1633
|
+
building.floors.create!(level: 2)
|
|
1634
|
+
end
|
|
1635
|
+
|
|
1636
|
+
let(:pending_touch_time) do
|
|
1637
|
+
Time.now + 60
|
|
1638
|
+
end
|
|
1639
|
+
|
|
1640
|
+
before do
|
|
1641
|
+
first_floor
|
|
1642
|
+
# Leave a pending touch on the other floor, at a different index of
|
|
1643
|
+
# the same array. Rewriting both that touch and the insert's own
|
|
1644
|
+
# touch to the positional operator collapses them onto one path and
|
|
1645
|
+
# touches the wrong floor.
|
|
1646
|
+
second_floor.updated_at = pending_touch_time
|
|
1647
|
+
end
|
|
1648
|
+
|
|
1649
|
+
it 'does not raise when creating a grandchild under the other floor' do
|
|
1650
|
+
expect { first_floor.sofas.create! }.not_to raise_error
|
|
1651
|
+
end
|
|
1652
|
+
|
|
1653
|
+
it 'touches the floor the grandchild was inserted under' do
|
|
1654
|
+
first_floor.sofas.create!
|
|
1655
|
+
building.reload
|
|
1656
|
+
expect(building.floors[0].updated_at).to be_within(5).of(Time.now)
|
|
1657
|
+
end
|
|
1658
|
+
|
|
1659
|
+
it 'preserves the pending touch on the sibling floor' do
|
|
1660
|
+
first_floor.sofas.create!
|
|
1661
|
+
building.reload
|
|
1662
|
+
expect(building.floors[1].updated_at.to_f)
|
|
1663
|
+
.to be_within(1).of(pending_touch_time.to_f)
|
|
1664
|
+
end
|
|
1665
|
+
end
|
|
1666
|
+
|
|
1667
|
+
context 'when the parent touch option names a custom field' do
|
|
1668
|
+
let(:building) do
|
|
1669
|
+
TouchableSpec::Embedded::Building.create!(title: 'Tower')
|
|
1670
|
+
end
|
|
1671
|
+
|
|
1672
|
+
it 'writes the custom touch field when creating an embedded child' do
|
|
1673
|
+
# Materialize the parent before the freeze so its updated_at differs
|
|
1674
|
+
# from the touch time, forcing the touch updates to merge into the
|
|
1675
|
+
# child's insert.
|
|
1676
|
+
building
|
|
1677
|
+
Timecop.freeze(Time.utc(2026, 1, 2, 3, 4, 5)) do
|
|
1678
|
+
building.waiting_rooms.create!
|
|
1679
|
+
building.reload
|
|
1680
|
+
expect(building.last_used_at).not_to be_nil
|
|
1681
|
+
expect(building.last_used_at.to_f)
|
|
1682
|
+
.to be_within(1).of(Time.utc(2026, 1, 2, 3, 4, 5).to_f)
|
|
1683
|
+
end
|
|
1684
|
+
end
|
|
1685
|
+
end
|
|
1686
|
+
|
|
1687
|
+
context 'when the models use Timestamps::Short' do
|
|
1688
|
+
let(:building) do
|
|
1689
|
+
TouchableSpec::Short::Building.create!
|
|
1690
|
+
end
|
|
1691
|
+
|
|
1692
|
+
let(:floor) do
|
|
1693
|
+
building.floors.create!
|
|
1694
|
+
end
|
|
1695
|
+
|
|
1696
|
+
before do
|
|
1697
|
+
building
|
|
1698
|
+
floor
|
|
1699
|
+
end
|
|
1700
|
+
|
|
1701
|
+
it 'merges the touch updates into the insert round-trip' do
|
|
1702
|
+
expect_query(1) do
|
|
1703
|
+
floor.gadgets.push(TouchableSpec::Short::Gadget.new)
|
|
1704
|
+
end
|
|
1705
|
+
end
|
|
1706
|
+
|
|
1707
|
+
it 'touches the parent chain through the aliased timestamp fields' do
|
|
1708
|
+
original_building_updated_at = building.u_at
|
|
1709
|
+
original_floor_updated_at = floor.u_at
|
|
1710
|
+
|
|
1711
|
+
Timecop.travel(Time.now + 10) do
|
|
1712
|
+
floor.gadgets.push(TouchableSpec::Short::Gadget.new)
|
|
1713
|
+
end
|
|
1714
|
+
|
|
1715
|
+
building.reload
|
|
1716
|
+
expect(building.u_at).to be > original_building_updated_at
|
|
1717
|
+
expect(building.floors.first.u_at).to be > original_floor_updated_at
|
|
1718
|
+
end
|
|
1719
|
+
end
|
|
1720
|
+
|
|
1721
|
+
context 'when a sibling has a pending touch and the touch callback does not run' do
|
|
1722
|
+
let(:building) do
|
|
1723
|
+
TouchableSpec::Embedded::Building.create!(title: 'Tower')
|
|
1724
|
+
end
|
|
1725
|
+
|
|
1726
|
+
let(:first_floor) do
|
|
1727
|
+
building.floors.create!(level: 1)
|
|
1728
|
+
end
|
|
1729
|
+
|
|
1730
|
+
let(:second_floor) do
|
|
1731
|
+
building.floors.create!(level: 2)
|
|
1732
|
+
end
|
|
1733
|
+
|
|
1734
|
+
let(:pending_touch_time) do
|
|
1735
|
+
Time.now + 60
|
|
1736
|
+
end
|
|
1737
|
+
|
|
1738
|
+
before do
|
|
1739
|
+
first_floor
|
|
1740
|
+
# Leave a pending touch on the other floor: rewriting it and this
|
|
1741
|
+
# chain's own touch would collapse both onto the same positional
|
|
1742
|
+
# path, so the touch updates cannot be merged into the insert.
|
|
1743
|
+
second_floor.updated_at = pending_touch_time
|
|
1744
|
+
end
|
|
1745
|
+
|
|
1746
|
+
it 'persists the deferred touches at insert time' do
|
|
1747
|
+
Mongoid::Touchable.suppress_touch_callbacks(TouchableSpec::Embedded::Sofa.name) do
|
|
1748
|
+
first_floor.sofas.push(TouchableSpec::Embedded::Sofa.new)
|
|
1749
|
+
end
|
|
1750
|
+
|
|
1751
|
+
building.reload
|
|
1752
|
+
expect(building.floors[1].updated_at.to_f)
|
|
1753
|
+
.to be_within(1).of(pending_touch_time.to_f)
|
|
1754
|
+
end
|
|
1755
|
+
end
|
|
1539
1756
|
end
|
|
1540
1757
|
end
|
|
@@ -7,10 +7,12 @@ module TouchableSpec
|
|
|
7
7
|
include Mongoid::Timestamps
|
|
8
8
|
|
|
9
9
|
field :title, type: String
|
|
10
|
+
field :last_used_at, type: Time
|
|
10
11
|
|
|
11
12
|
embeds_many :entrances, class_name: 'TouchableSpec::Embedded::Entrance'
|
|
12
13
|
embeds_many :floors, class_name: 'TouchableSpec::Embedded::Floor'
|
|
13
14
|
embeds_one :lobby, class_name: 'TouchableSpec::Embedded::Lobby'
|
|
15
|
+
embeds_many :waiting_rooms, class_name: 'TouchableSpec::Embedded::WaitingRoom'
|
|
14
16
|
end
|
|
15
17
|
|
|
16
18
|
class Lobby
|
|
@@ -75,6 +77,41 @@ module TouchableSpec
|
|
|
75
77
|
|
|
76
78
|
embedded_in :floor, touch: true, class_name: 'TouchableSpec::Embedded::Floor'
|
|
77
79
|
end
|
|
80
|
+
|
|
81
|
+
class WaitingRoom
|
|
82
|
+
include Mongoid::Document
|
|
83
|
+
include Mongoid::Timestamps
|
|
84
|
+
|
|
85
|
+
field :name, type: String
|
|
86
|
+
|
|
87
|
+
embedded_in :building, touch: :last_used_at,
|
|
88
|
+
class_name: 'TouchableSpec::Embedded::Building'
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
module Short
|
|
93
|
+
class Building
|
|
94
|
+
include Mongoid::Document
|
|
95
|
+
include Mongoid::Timestamps::Short
|
|
96
|
+
|
|
97
|
+
embeds_many :floors, class_name: 'TouchableSpec::Short::Floor'
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
class Floor
|
|
101
|
+
include Mongoid::Document
|
|
102
|
+
include Mongoid::Timestamps::Short
|
|
103
|
+
|
|
104
|
+
embedded_in :building, touch: true, class_name: 'TouchableSpec::Short::Building'
|
|
105
|
+
|
|
106
|
+
embeds_many :gadgets, class_name: 'TouchableSpec::Short::Gadget'
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
class Gadget
|
|
110
|
+
include Mongoid::Document
|
|
111
|
+
include Mongoid::Timestamps::Short
|
|
112
|
+
|
|
113
|
+
embedded_in :floor, touch: true, class_name: 'TouchableSpec::Short::Floor'
|
|
114
|
+
end
|
|
78
115
|
end
|
|
79
116
|
|
|
80
117
|
module Referenced
|
|
@@ -203,4 +203,100 @@ module Crypt
|
|
|
203
203
|
|
|
204
204
|
embeds_one :missing_note, class_name: 'Crypt::MissingNote'
|
|
205
205
|
end
|
|
206
|
+
|
|
207
|
+
# Two unrelated models stored in one collection, each with its own encrypted
|
|
208
|
+
# field.
|
|
209
|
+
class Badge
|
|
210
|
+
include Mongoid::Document
|
|
211
|
+
|
|
212
|
+
store_in collection: 'crypt_badges'
|
|
213
|
+
|
|
214
|
+
encrypt_with key_id: 'grolrnFVSSW9Gq04Q87R9Q==', deterministic: true
|
|
215
|
+
|
|
216
|
+
field :serial, type: String, encrypt: true
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
class BadgeScan
|
|
220
|
+
include Mongoid::Document
|
|
221
|
+
|
|
222
|
+
store_in collection: 'crypt_badges'
|
|
223
|
+
|
|
224
|
+
encrypt_with key_id: 'grolrnFVSSW9Gq04Q87R9Q==', deterministic: true
|
|
225
|
+
|
|
226
|
+
field :holder, type: String, encrypt: true
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# Single collection inheritance. Only Member is registered in
|
|
230
|
+
# Mongoid.models; the subclasses are not.
|
|
231
|
+
class Member
|
|
232
|
+
include Mongoid::Document
|
|
233
|
+
|
|
234
|
+
encrypt_with key_id: 'grolrnFVSSW9Gq04Q87R9Q==', deterministic: true
|
|
235
|
+
|
|
236
|
+
field :ssn, type: String, encrypt: true
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
class Employee < Member
|
|
240
|
+
field :salary, type: String, encrypt: true
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
class Contractor < Member
|
|
244
|
+
field :rate, type: String, encrypt: true
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# Single collection inheritance where only the subclass is encrypted.
|
|
248
|
+
class Listing
|
|
249
|
+
include Mongoid::Document
|
|
250
|
+
|
|
251
|
+
field :title, type: String
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
class PrivateListing < Listing
|
|
255
|
+
encrypt_with key_id: 'grolrnFVSSW9Gq04Q87R9Q==', deterministic: true
|
|
256
|
+
|
|
257
|
+
field :owner_ssn, type: String, encrypt: true
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# An embeds_one target whose subclass adds an encrypted field.
|
|
261
|
+
class Box
|
|
262
|
+
include Mongoid::Document
|
|
263
|
+
|
|
264
|
+
encrypt_with key_id: 'grolrnFVSSW9Gq04Q87R9Q==', deterministic: true
|
|
265
|
+
|
|
266
|
+
embeds_one :item, class_name: 'Crypt::Item'
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
class Item
|
|
270
|
+
include Mongoid::Document
|
|
271
|
+
|
|
272
|
+
field :label, type: String, encrypt: true
|
|
273
|
+
|
|
274
|
+
embedded_in :box, class_name: 'Crypt::Box'
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
class SealedItem < Item
|
|
278
|
+
field :seal, type: String, encrypt: true
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# An embeds_one target with no encrypted field, whose subclass has one.
|
|
282
|
+
# Nothing on Locker or Content declares encryption.
|
|
283
|
+
class Locker
|
|
284
|
+
include Mongoid::Document
|
|
285
|
+
|
|
286
|
+
embeds_one :content, class_name: 'Crypt::Content'
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
class Content
|
|
290
|
+
include Mongoid::Document
|
|
291
|
+
|
|
292
|
+
field :label, type: String
|
|
293
|
+
|
|
294
|
+
embedded_in :locker, class_name: 'Crypt::Locker'
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
class SecretContent < Content
|
|
298
|
+
encrypt_with key_id: 'grolrnFVSSW9Gq04Q87R9Q==', deterministic: true
|
|
299
|
+
|
|
300
|
+
field :code, type: String, encrypt: true
|
|
301
|
+
end
|
|
206
302
|
end
|
|
@@ -22,4 +22,69 @@ module ModifierModels
|
|
|
22
22
|
embedded_in :book, class_name: 'ModifierModels::Book'
|
|
23
23
|
field :text, type: String
|
|
24
24
|
end
|
|
25
|
+
|
|
26
|
+
class Roster
|
|
27
|
+
include Mongoid::Document
|
|
28
|
+
|
|
29
|
+
embeds_many :players, class_name: 'ModifierModels::Player'
|
|
30
|
+
accepts_nested_attributes_for :players, allow_destroy: true
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
class Player
|
|
34
|
+
include Mongoid::Document
|
|
35
|
+
|
|
36
|
+
embedded_in :roster, class_name: 'ModifierModels::Roster'
|
|
37
|
+
embeds_one :medal, class_name: 'ModifierModels::Medal'
|
|
38
|
+
has_and_belongs_to_many :badges, inverse_of: nil, class_name: 'ModifierModels::Badge'
|
|
39
|
+
embeds_many :awards, class_name: 'ModifierModels::Award'
|
|
40
|
+
accepts_nested_attributes_for :awards, allow_destroy: true
|
|
41
|
+
field :nickname, type: String
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class Award
|
|
45
|
+
include Mongoid::Document
|
|
46
|
+
|
|
47
|
+
embedded_in :player, class_name: 'ModifierModels::Player'
|
|
48
|
+
has_and_belongs_to_many :badges, inverse_of: nil, class_name: 'ModifierModels::Badge'
|
|
49
|
+
field :name, type: String
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
class Medal
|
|
53
|
+
include Mongoid::Document
|
|
54
|
+
|
|
55
|
+
embedded_in :player, class_name: 'ModifierModels::Player'
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
class Badge
|
|
59
|
+
include Mongoid::Document
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
class Cabinet
|
|
63
|
+
include Mongoid::Document
|
|
64
|
+
|
|
65
|
+
embeds_one :drawer, class_name: 'ModifierModels::Drawer', autobuild: true
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
class Drawer
|
|
69
|
+
include Mongoid::Document
|
|
70
|
+
|
|
71
|
+
field :matcher, type: String
|
|
72
|
+
embedded_in :cabinet, class_name: 'ModifierModels::Cabinet'
|
|
73
|
+
embeds_many :items, class_name: 'ModifierModels::Item'
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
class Item
|
|
77
|
+
include Mongoid::Document
|
|
78
|
+
|
|
79
|
+
field :name, type: String
|
|
80
|
+
embedded_in :drawer, class_name: 'ModifierModels::Drawer'
|
|
81
|
+
embeds_many :widgets, class_name: 'ModifierModels::Widget'
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
class Widget
|
|
85
|
+
include Mongoid::Document
|
|
86
|
+
|
|
87
|
+
field :label, type: String
|
|
88
|
+
embedded_in :item, class_name: 'ModifierModels::Item'
|
|
89
|
+
end
|
|
25
90
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mongoid
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 9.1.
|
|
4
|
+
version: 9.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- The MongoDB Ruby Team
|
|
@@ -317,6 +317,7 @@ files:
|
|
|
317
317
|
- lib/mongoid/errors/invalid_discriminator_key_target.rb
|
|
318
318
|
- lib/mongoid/errors/invalid_dot_dollar_assignment.rb
|
|
319
319
|
- lib/mongoid/errors/invalid_elem_match_operator.rb
|
|
320
|
+
- lib/mongoid/errors/invalid_encryption_schema.rb
|
|
320
321
|
- lib/mongoid/errors/invalid_estimated_count_criteria.rb
|
|
321
322
|
- lib/mongoid/errors/invalid_estimated_count_scoping.rb
|
|
322
323
|
- lib/mongoid/errors/invalid_expression_operator.rb
|
|
@@ -529,6 +530,7 @@ files:
|
|
|
529
530
|
- spec/integration/active_job_spec.rb
|
|
530
531
|
- spec/integration/app_spec.rb
|
|
531
532
|
- spec/integration/associations/belongs_to_spec.rb
|
|
533
|
+
- spec/integration/associations/embedded_delayed_atomic_sets_spec.rb
|
|
532
534
|
- spec/integration/associations/embedded_dirty_spec.rb
|
|
533
535
|
- spec/integration/associations/embedded_spec.rb
|
|
534
536
|
- spec/integration/associations/embeds_many_spec.rb
|
|
@@ -1287,7 +1289,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
1287
1289
|
- !ruby/object:Gem::Version
|
|
1288
1290
|
version: 1.3.6
|
|
1289
1291
|
requirements: []
|
|
1290
|
-
rubygems_version: 4.0.
|
|
1292
|
+
rubygems_version: 4.0.24
|
|
1291
1293
|
specification_version: 4
|
|
1292
1294
|
summary: Elegant Persistence in Ruby for MongoDB.
|
|
1293
1295
|
test_files:
|
|
@@ -1297,6 +1299,7 @@ test_files:
|
|
|
1297
1299
|
- spec/integration/active_job_spec.rb
|
|
1298
1300
|
- spec/integration/app_spec.rb
|
|
1299
1301
|
- spec/integration/associations/belongs_to_spec.rb
|
|
1302
|
+
- spec/integration/associations/embedded_delayed_atomic_sets_spec.rb
|
|
1300
1303
|
- spec/integration/associations/embedded_dirty_spec.rb
|
|
1301
1304
|
- spec/integration/associations/embedded_spec.rb
|
|
1302
1305
|
- spec/integration/associations/embeds_many_spec.rb
|