mongoid-pre 2.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.
- data/.gitignore +6 -0
- data/.watchr +24 -0
- data/MIT_LICENSE +20 -0
- data/README.rdoc +49 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/caliper.yml +4 -0
- data/lib/mongoid.rb +135 -0
- data/lib/mongoid/associations.rb +263 -0
- data/lib/mongoid/associations/belongs_to_related.rb +59 -0
- data/lib/mongoid/associations/embedded_in.rb +64 -0
- data/lib/mongoid/associations/embeds_many.rb +193 -0
- data/lib/mongoid/associations/embeds_one.rb +95 -0
- data/lib/mongoid/associations/has_many_related.rb +133 -0
- data/lib/mongoid/associations/has_one_related.rb +81 -0
- data/lib/mongoid/associations/meta_data.rb +28 -0
- data/lib/mongoid/associations/options.rb +52 -0
- data/lib/mongoid/associations/proxy.rb +31 -0
- data/lib/mongoid/attributes.rb +185 -0
- data/lib/mongoid/callbacks.rb +18 -0
- data/lib/mongoid/collection.rb +119 -0
- data/lib/mongoid/collections/cyclic_iterator.rb +34 -0
- data/lib/mongoid/collections/master.rb +28 -0
- data/lib/mongoid/collections/mimic.rb +46 -0
- data/lib/mongoid/collections/operations.rb +41 -0
- data/lib/mongoid/collections/slaves.rb +44 -0
- data/lib/mongoid/commands.rb +161 -0
- data/lib/mongoid/commands/create.rb +19 -0
- data/lib/mongoid/commands/delete.rb +16 -0
- data/lib/mongoid/commands/delete_all.rb +25 -0
- data/lib/mongoid/commands/deletion.rb +18 -0
- data/lib/mongoid/commands/destroy.rb +17 -0
- data/lib/mongoid/commands/destroy_all.rb +25 -0
- data/lib/mongoid/commands/save.rb +30 -0
- data/lib/mongoid/components.rb +31 -0
- data/lib/mongoid/config.rb +86 -0
- data/lib/mongoid/contexts.rb +25 -0
- data/lib/mongoid/contexts/enumerable.rb +151 -0
- data/lib/mongoid/contexts/ids.rb +25 -0
- data/lib/mongoid/contexts/mongo.rb +285 -0
- data/lib/mongoid/contexts/paging.rb +42 -0
- data/lib/mongoid/criteria.rb +239 -0
- data/lib/mongoid/criterion/complex.rb +21 -0
- data/lib/mongoid/criterion/exclusion.rb +65 -0
- data/lib/mongoid/criterion/inclusion.rb +93 -0
- data/lib/mongoid/criterion/optional.rb +136 -0
- data/lib/mongoid/cursor.rb +82 -0
- data/lib/mongoid/deprecation.rb +22 -0
- data/lib/mongoid/dirty.rb +203 -0
- data/lib/mongoid/document.rb +306 -0
- data/lib/mongoid/errors.rb +77 -0
- data/lib/mongoid/extensions.rb +99 -0
- data/lib/mongoid/extensions/array/accessors.rb +17 -0
- data/lib/mongoid/extensions/array/aliasing.rb +4 -0
- data/lib/mongoid/extensions/array/assimilation.rb +26 -0
- data/lib/mongoid/extensions/array/conversions.rb +27 -0
- data/lib/mongoid/extensions/array/parentization.rb +13 -0
- data/lib/mongoid/extensions/big_decimal/conversions.rb +19 -0
- data/lib/mongoid/extensions/binary/conversions.rb +17 -0
- data/lib/mongoid/extensions/boolean/conversions.rb +16 -0
- data/lib/mongoid/extensions/date/conversions.rb +15 -0
- data/lib/mongoid/extensions/datetime/conversions.rb +17 -0
- data/lib/mongoid/extensions/float/conversions.rb +16 -0
- data/lib/mongoid/extensions/hash/accessors.rb +38 -0
- data/lib/mongoid/extensions/hash/assimilation.rb +30 -0
- data/lib/mongoid/extensions/hash/conversions.rb +15 -0
- data/lib/mongoid/extensions/hash/criteria_helpers.rb +20 -0
- data/lib/mongoid/extensions/hash/scoping.rb +12 -0
- data/lib/mongoid/extensions/integer/conversions.rb +16 -0
- data/lib/mongoid/extensions/nil/assimilation.rb +13 -0
- data/lib/mongoid/extensions/object/conversions.rb +27 -0
- data/lib/mongoid/extensions/objectid/conversions.rb +15 -0
- data/lib/mongoid/extensions/proc/scoping.rb +12 -0
- data/lib/mongoid/extensions/string/conversions.rb +15 -0
- data/lib/mongoid/extensions/string/inflections.rb +97 -0
- data/lib/mongoid/extensions/symbol/inflections.rb +36 -0
- data/lib/mongoid/extensions/time/conversions.rb +18 -0
- data/lib/mongoid/extras.rb +61 -0
- data/lib/mongoid/factory.rb +19 -0
- data/lib/mongoid/field.rb +52 -0
- data/lib/mongoid/fields.rb +62 -0
- data/lib/mongoid/finders.rb +136 -0
- data/lib/mongoid/identity.rb +39 -0
- data/lib/mongoid/indexes.rb +27 -0
- data/lib/mongoid/javascript.rb +21 -0
- data/lib/mongoid/javascript/functions.yml +37 -0
- data/lib/mongoid/matchers.rb +36 -0
- data/lib/mongoid/matchers/all.rb +11 -0
- data/lib/mongoid/matchers/default.rb +26 -0
- data/lib/mongoid/matchers/exists.rb +13 -0
- data/lib/mongoid/matchers/gt.rb +11 -0
- data/lib/mongoid/matchers/gte.rb +11 -0
- data/lib/mongoid/matchers/in.rb +11 -0
- data/lib/mongoid/matchers/lt.rb +11 -0
- data/lib/mongoid/matchers/lte.rb +11 -0
- data/lib/mongoid/matchers/ne.rb +11 -0
- data/lib/mongoid/matchers/nin.rb +11 -0
- data/lib/mongoid/matchers/size.rb +11 -0
- data/lib/mongoid/memoization.rb +27 -0
- data/lib/mongoid/named_scope.rb +42 -0
- data/lib/mongoid/observable.rb +30 -0
- data/lib/mongoid/paths.rb +54 -0
- data/lib/mongoid/persistence.rb +27 -0
- data/lib/mongoid/persistence/command.rb +20 -0
- data/lib/mongoid/persistence/insert.rb +71 -0
- data/lib/mongoid/persistence/update.rb +78 -0
- data/lib/mongoid/scope.rb +75 -0
- data/lib/mongoid/state.rb +32 -0
- data/lib/mongoid/timestamps.rb +27 -0
- data/lib/mongoid/validations.rb +51 -0
- data/lib/mongoid/validations/associated.rb +32 -0
- data/lib/mongoid/validations/locale/en.yml +4 -0
- data/lib/mongoid/validations/uniqueness.rb +22 -0
- data/lib/mongoid/versioning.rb +26 -0
- data/mongoid.gemspec +413 -0
- data/perf/benchmark.rb +77 -0
- data/spec/integration/mongoid/associations_spec.rb +340 -0
- data/spec/integration/mongoid/attributes_spec.rb +22 -0
- data/spec/integration/mongoid/commands_spec.rb +230 -0
- data/spec/integration/mongoid/contexts/enumerable_spec.rb +33 -0
- data/spec/integration/mongoid/criteria_spec.rb +272 -0
- data/spec/integration/mongoid/dirty_spec.rb +70 -0
- data/spec/integration/mongoid/document_spec.rb +650 -0
- data/spec/integration/mongoid/extensions_spec.rb +22 -0
- data/spec/integration/mongoid/finders_spec.rb +119 -0
- data/spec/integration/mongoid/inheritance_spec.rb +137 -0
- data/spec/integration/mongoid/named_scope_spec.rb +46 -0
- data/spec/integration/mongoid/persistence/update_spec.rb +46 -0
- data/spec/models/address.rb +39 -0
- data/spec/models/animal.rb +6 -0
- data/spec/models/callbacks.rb +18 -0
- data/spec/models/comment.rb +8 -0
- data/spec/models/country_code.rb +6 -0
- data/spec/models/employer.rb +5 -0
- data/spec/models/game.rb +7 -0
- data/spec/models/inheritance.rb +56 -0
- data/spec/models/location.rb +5 -0
- data/spec/models/mixed_drink.rb +4 -0
- data/spec/models/name.rb +13 -0
- data/spec/models/namespacing.rb +11 -0
- data/spec/models/patient.rb +6 -0
- data/spec/models/person.rb +99 -0
- data/spec/models/pet.rb +7 -0
- data/spec/models/pet_owner.rb +6 -0
- data/spec/models/phone.rb +7 -0
- data/spec/models/post.rb +15 -0
- data/spec/models/translation.rb +5 -0
- data/spec/models/vet_visit.rb +5 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/unit/mongoid/associations/belongs_to_related_spec.rb +145 -0
- data/spec/unit/mongoid/associations/embedded_in_spec.rb +193 -0
- data/spec/unit/mongoid/associations/embeds_many_spec.rb +516 -0
- data/spec/unit/mongoid/associations/embeds_one_spec.rb +282 -0
- data/spec/unit/mongoid/associations/has_many_related_spec.rb +418 -0
- data/spec/unit/mongoid/associations/has_one_related_spec.rb +179 -0
- data/spec/unit/mongoid/associations/meta_data_spec.rb +88 -0
- data/spec/unit/mongoid/associations/options_spec.rb +192 -0
- data/spec/unit/mongoid/associations_spec.rb +595 -0
- data/spec/unit/mongoid/attributes_spec.rb +507 -0
- data/spec/unit/mongoid/callbacks_spec.rb +55 -0
- data/spec/unit/mongoid/collection_spec.rb +187 -0
- data/spec/unit/mongoid/collections/cyclic_iterator_spec.rb +75 -0
- data/spec/unit/mongoid/collections/master_spec.rb +41 -0
- data/spec/unit/mongoid/collections/mimic_spec.rb +43 -0
- data/spec/unit/mongoid/collections/slaves_spec.rb +81 -0
- data/spec/unit/mongoid/commands/create_spec.rb +31 -0
- data/spec/unit/mongoid/commands/delete_all_spec.rb +59 -0
- data/spec/unit/mongoid/commands/delete_spec.rb +38 -0
- data/spec/unit/mongoid/commands/destroy_all_spec.rb +21 -0
- data/spec/unit/mongoid/commands/destroy_spec.rb +51 -0
- data/spec/unit/mongoid/commands/save_spec.rb +107 -0
- data/spec/unit/mongoid/commands_spec.rb +270 -0
- data/spec/unit/mongoid/config_spec.rb +176 -0
- data/spec/unit/mongoid/contexts/enumerable_spec.rb +421 -0
- data/spec/unit/mongoid/contexts/mongo_spec.rb +682 -0
- data/spec/unit/mongoid/contexts_spec.rb +25 -0
- data/spec/unit/mongoid/criteria_spec.rb +824 -0
- data/spec/unit/mongoid/criterion/complex_spec.rb +19 -0
- data/spec/unit/mongoid/criterion/exclusion_spec.rb +91 -0
- data/spec/unit/mongoid/criterion/inclusion_spec.rb +219 -0
- data/spec/unit/mongoid/criterion/optional_spec.rb +319 -0
- data/spec/unit/mongoid/cursor_spec.rb +74 -0
- data/spec/unit/mongoid/deprecation_spec.rb +24 -0
- data/spec/unit/mongoid/dirty_spec.rb +286 -0
- data/spec/unit/mongoid/document_spec.rb +818 -0
- data/spec/unit/mongoid/errors_spec.rb +103 -0
- data/spec/unit/mongoid/extensions/array/accessors_spec.rb +50 -0
- data/spec/unit/mongoid/extensions/array/assimilation_spec.rb +24 -0
- data/spec/unit/mongoid/extensions/array/conversions_spec.rb +35 -0
- data/spec/unit/mongoid/extensions/array/parentization_spec.rb +20 -0
- data/spec/unit/mongoid/extensions/big_decimal/conversions_spec.rb +22 -0
- data/spec/unit/mongoid/extensions/binary/conversions_spec.rb +22 -0
- data/spec/unit/mongoid/extensions/boolean/conversions_spec.rb +49 -0
- data/spec/unit/mongoid/extensions/date/conversions_spec.rb +102 -0
- data/spec/unit/mongoid/extensions/datetime/conversions_spec.rb +67 -0
- data/spec/unit/mongoid/extensions/float/conversions_spec.rb +61 -0
- data/spec/unit/mongoid/extensions/hash/accessors_spec.rb +184 -0
- data/spec/unit/mongoid/extensions/hash/assimilation_spec.rb +46 -0
- data/spec/unit/mongoid/extensions/hash/conversions_spec.rb +21 -0
- data/spec/unit/mongoid/extensions/hash/criteria_helpers_spec.rb +17 -0
- data/spec/unit/mongoid/extensions/hash/scoping_spec.rb +14 -0
- data/spec/unit/mongoid/extensions/integer/conversions_spec.rb +61 -0
- data/spec/unit/mongoid/extensions/nil/assimilation_spec.rb +24 -0
- data/spec/unit/mongoid/extensions/object/conversions_spec.rb +57 -0
- data/spec/unit/mongoid/extensions/proc/scoping_spec.rb +34 -0
- data/spec/unit/mongoid/extensions/string/conversions_spec.rb +17 -0
- data/spec/unit/mongoid/extensions/string/inflections_spec.rb +208 -0
- data/spec/unit/mongoid/extensions/symbol/inflections_spec.rb +91 -0
- data/spec/unit/mongoid/extensions/time/conversions_spec.rb +70 -0
- data/spec/unit/mongoid/extras_spec.rb +102 -0
- data/spec/unit/mongoid/factory_spec.rb +31 -0
- data/spec/unit/mongoid/field_spec.rb +143 -0
- data/spec/unit/mongoid/fields_spec.rb +181 -0
- data/spec/unit/mongoid/finders_spec.rb +404 -0
- data/spec/unit/mongoid/identity_spec.rb +109 -0
- data/spec/unit/mongoid/indexes_spec.rb +93 -0
- data/spec/unit/mongoid/javascript_spec.rb +48 -0
- data/spec/unit/mongoid/matchers/all_spec.rb +27 -0
- data/spec/unit/mongoid/matchers/default_spec.rb +27 -0
- data/spec/unit/mongoid/matchers/exists_spec.rb +56 -0
- data/spec/unit/mongoid/matchers/gt_spec.rb +39 -0
- data/spec/unit/mongoid/matchers/gte_spec.rb +49 -0
- data/spec/unit/mongoid/matchers/in_spec.rb +27 -0
- data/spec/unit/mongoid/matchers/lt_spec.rb +39 -0
- data/spec/unit/mongoid/matchers/lte_spec.rb +49 -0
- data/spec/unit/mongoid/matchers/ne_spec.rb +27 -0
- data/spec/unit/mongoid/matchers/nin_spec.rb +27 -0
- data/spec/unit/mongoid/matchers/size_spec.rb +27 -0
- data/spec/unit/mongoid/matchers_spec.rb +329 -0
- data/spec/unit/mongoid/memoization_spec.rb +75 -0
- data/spec/unit/mongoid/named_scope_spec.rb +123 -0
- data/spec/unit/mongoid/observable_spec.rb +46 -0
- data/spec/unit/mongoid/paths_spec.rb +124 -0
- data/spec/unit/mongoid/persistence/insert_spec.rb +175 -0
- data/spec/unit/mongoid/persistence/update_spec.rb +148 -0
- data/spec/unit/mongoid/persistence_spec.rb +40 -0
- data/spec/unit/mongoid/scope_spec.rb +240 -0
- data/spec/unit/mongoid/state_spec.rb +83 -0
- data/spec/unit/mongoid/timestamps_spec.rb +25 -0
- data/spec/unit/mongoid/validations/associated_spec.rb +103 -0
- data/spec/unit/mongoid/validations/uniqueness_spec.rb +47 -0
- data/spec/unit/mongoid/validations_spec.rb +190 -0
- data/spec/unit/mongoid/versioning_spec.rb +41 -0
- data/spec/unit/mongoid_spec.rb +46 -0
- metadata +476 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc:
|
|
3
|
+
module Associations #:nodoc:
|
|
4
|
+
class BelongsToRelated #:nodoc:
|
|
5
|
+
include Proxy
|
|
6
|
+
|
|
7
|
+
# Initializing a related association only requires looking up the object
|
|
8
|
+
# by its id.
|
|
9
|
+
#
|
|
10
|
+
# Options:
|
|
11
|
+
#
|
|
12
|
+
# document: The +Document+ that contains the relationship.
|
|
13
|
+
# options: The association +Options+.
|
|
14
|
+
def initialize(document, foreign_key, options, target = nil)
|
|
15
|
+
@options = options
|
|
16
|
+
@target = target || options.klass.find(foreign_key)
|
|
17
|
+
extends(options)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class << self
|
|
21
|
+
# Instantiate a new +BelongsToRelated+ or return nil if the foreign key is
|
|
22
|
+
# nil. It is preferrable to use this method over the traditional call
|
|
23
|
+
# to new.
|
|
24
|
+
#
|
|
25
|
+
# Options:
|
|
26
|
+
#
|
|
27
|
+
# document: The +Document+ that contains the relationship.
|
|
28
|
+
# options: The association +Options+.
|
|
29
|
+
def instantiate(document, options, target = nil)
|
|
30
|
+
foreign_key = document.send(options.foreign_key)
|
|
31
|
+
foreign_key.blank? ? nil : new(document, foreign_key, options, target)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Returns the macro used to create the association.
|
|
35
|
+
def macro
|
|
36
|
+
:belongs_to_related
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Perform an update of the relationship of the parent and child. This
|
|
40
|
+
# will assimilate the child +Document+ into the parent's object graph.
|
|
41
|
+
#
|
|
42
|
+
# Options:
|
|
43
|
+
#
|
|
44
|
+
# target: The target(parent) object
|
|
45
|
+
# document: The +Document+ to update.
|
|
46
|
+
# options: The association +Options+
|
|
47
|
+
#
|
|
48
|
+
# Example:
|
|
49
|
+
#
|
|
50
|
+
# <tt>BelongsToRelated.update(person, game, options)</tt>
|
|
51
|
+
def update(target, document, options)
|
|
52
|
+
document.send("#{options.foreign_key}=", target ? target.id : nil)
|
|
53
|
+
instantiate(document, options, target)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc:
|
|
3
|
+
module Associations #:nodoc:
|
|
4
|
+
class EmbeddedIn #:nodoc:
|
|
5
|
+
include Proxy
|
|
6
|
+
|
|
7
|
+
# Creates the new association by setting the internal
|
|
8
|
+
# target as the passed in Document. This should be the
|
|
9
|
+
# parent.
|
|
10
|
+
#
|
|
11
|
+
# All method calls on this object will then be delegated
|
|
12
|
+
# to the internal document itself.
|
|
13
|
+
#
|
|
14
|
+
# Options:
|
|
15
|
+
#
|
|
16
|
+
# target: The parent +Document+
|
|
17
|
+
# options: The association options
|
|
18
|
+
def initialize(target, options)
|
|
19
|
+
@target, @options = target, options
|
|
20
|
+
extends(options)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Returns the parent document. The id param is present for
|
|
24
|
+
# compatibility with rails, however this could be overwritten
|
|
25
|
+
# in the future.
|
|
26
|
+
def find(id)
|
|
27
|
+
@target
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class << self
|
|
31
|
+
# Creates the new association by setting the internal
|
|
32
|
+
# document as the passed in Document. This should be the
|
|
33
|
+
# parent.
|
|
34
|
+
#
|
|
35
|
+
# Options:
|
|
36
|
+
#
|
|
37
|
+
# document: The parent +Document+
|
|
38
|
+
# options: The association options
|
|
39
|
+
def instantiate(document, options)
|
|
40
|
+
target = document._parent
|
|
41
|
+
target.nil? ? nil : new(target, options)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Returns the macro used to create the association.
|
|
45
|
+
def macro
|
|
46
|
+
:embedded_in
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Perform an update of the relationship of the parent and child. This
|
|
50
|
+
# is initialized by setting a parent object as the association on the
|
|
51
|
+
# +Document+. Will properly set an embeds_one or an embeds_many.
|
|
52
|
+
#
|
|
53
|
+
# Returns:
|
|
54
|
+
#
|
|
55
|
+
# A new +EmbeddedIn+ association proxy.
|
|
56
|
+
def update(target, child, options)
|
|
57
|
+
child.parentize(target, options.inverse_of)
|
|
58
|
+
child.notify
|
|
59
|
+
instantiate(child, options)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc:
|
|
3
|
+
module Associations #:nodoc:
|
|
4
|
+
class EmbedsMany
|
|
5
|
+
include Proxy
|
|
6
|
+
|
|
7
|
+
attr_accessor :association_name, :klass
|
|
8
|
+
|
|
9
|
+
# Appends the object to the +Array+, setting its parent in
|
|
10
|
+
# the process.
|
|
11
|
+
def <<(*documents)
|
|
12
|
+
documents.flatten.each do |doc|
|
|
13
|
+
doc.parentize(@parent, @association_name)
|
|
14
|
+
@target << doc
|
|
15
|
+
doc.notify
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
alias :concat :<<
|
|
20
|
+
alias :push :<<
|
|
21
|
+
|
|
22
|
+
# Clears the association, and notifies the parents of the removal.
|
|
23
|
+
def clear
|
|
24
|
+
unless @target.empty?
|
|
25
|
+
document = @target.first
|
|
26
|
+
document.notify_observers(document, true)
|
|
27
|
+
@target.clear
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Builds a new Document and adds it to the association collection. The
|
|
32
|
+
# document created will be of the same class as the others in the
|
|
33
|
+
# association, and the attributes will be passed into the constructor.
|
|
34
|
+
#
|
|
35
|
+
# Returns:
|
|
36
|
+
#
|
|
37
|
+
# The newly created Document.
|
|
38
|
+
def build(attrs = {}, type = nil)
|
|
39
|
+
document = type ? type.instantiate : @klass.instantiate
|
|
40
|
+
document.parentize(@parent, @association_name)
|
|
41
|
+
document.write_attributes(attrs)
|
|
42
|
+
@target << document
|
|
43
|
+
document
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Creates a new Document and adds it to the association collection. The
|
|
47
|
+
# document created will be of the same class as the others in the
|
|
48
|
+
# association, and the attributes will be passed into the constructor and
|
|
49
|
+
# the new object will then be saved.
|
|
50
|
+
#
|
|
51
|
+
# Returns:
|
|
52
|
+
#
|
|
53
|
+
# The newly created Document.
|
|
54
|
+
def create(attrs = {}, type = nil)
|
|
55
|
+
object = build(attrs, type)
|
|
56
|
+
object.run_callbacks(:create) { object.save }; object
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Creates a new Document and adds it to the association collection. The
|
|
60
|
+
# document created will be of the same class as the others in the
|
|
61
|
+
# association, and the attributes will be passed into the constructor and
|
|
62
|
+
# the new object will then be saved. If validation fails an error will
|
|
63
|
+
# get raised.
|
|
64
|
+
#
|
|
65
|
+
# Returns:
|
|
66
|
+
#
|
|
67
|
+
# The newly created Document.
|
|
68
|
+
def create!(attrs = {}, type = nil)
|
|
69
|
+
document = create(attrs, type)
|
|
70
|
+
errors = document.errors
|
|
71
|
+
raise Errors::Validations.new(errors) unless errors.empty?
|
|
72
|
+
document
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Finds a document in this association.
|
|
76
|
+
#
|
|
77
|
+
# If :all is passed, returns all the documents
|
|
78
|
+
#
|
|
79
|
+
# If an id is passed, will return the document for that id.
|
|
80
|
+
#
|
|
81
|
+
# Returns:
|
|
82
|
+
#
|
|
83
|
+
# Array or single Document.
|
|
84
|
+
def find(param)
|
|
85
|
+
return @target if param == :all
|
|
86
|
+
return detect { |document| document.id == param }
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Creates the new association by finding the attributes in
|
|
90
|
+
# the parent document with its name, and instantiating a
|
|
91
|
+
# new document for each one found. These will then be put in an
|
|
92
|
+
# internal array.
|
|
93
|
+
#
|
|
94
|
+
# This then delegated all methods to the array class since this is
|
|
95
|
+
# essentially a proxy to an array itself.
|
|
96
|
+
#
|
|
97
|
+
# Options:
|
|
98
|
+
#
|
|
99
|
+
# parent: The parent document to the association.
|
|
100
|
+
# options: The association options.
|
|
101
|
+
def initialize(parent, options)
|
|
102
|
+
@parent, @association_name = parent, options.name
|
|
103
|
+
@klass, @options = options.klass, options
|
|
104
|
+
initialize_each(parent.raw_attributes[@association_name])
|
|
105
|
+
extends(options)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# If the target array does not respond to the supplied method then try to
|
|
109
|
+
# find a named scope or criteria on the class and send the call there.
|
|
110
|
+
#
|
|
111
|
+
# If the method exists on the array, use the default proxy behavior.
|
|
112
|
+
def method_missing(name, *args, &block)
|
|
113
|
+
unless @target.respond_to?(name)
|
|
114
|
+
object = @klass.send(name, *args)
|
|
115
|
+
object.documents = @target
|
|
116
|
+
return object
|
|
117
|
+
end
|
|
118
|
+
super
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Used for setting associations via a nested attributes setter from the
|
|
122
|
+
# parent +Document+.
|
|
123
|
+
#
|
|
124
|
+
# Options:
|
|
125
|
+
#
|
|
126
|
+
# attributes: A +Hash+ of integer keys and +Hash+ values.
|
|
127
|
+
#
|
|
128
|
+
# Returns:
|
|
129
|
+
#
|
|
130
|
+
# The newly build target Document.
|
|
131
|
+
def nested_build(attributes)
|
|
132
|
+
attributes.values.each do |attrs|
|
|
133
|
+
build(attrs)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Paginate the association. Will create a new criteria, set the documents
|
|
138
|
+
# on it and execute in an enumerable context.
|
|
139
|
+
#
|
|
140
|
+
# Options:
|
|
141
|
+
#
|
|
142
|
+
# options: A +Hash+ of pagination options.
|
|
143
|
+
#
|
|
144
|
+
# Returns:
|
|
145
|
+
#
|
|
146
|
+
# A +WillPaginate::Collection+.
|
|
147
|
+
def paginate(options)
|
|
148
|
+
criteria = Mongoid::Criteria.translate(@klass, options)
|
|
149
|
+
criteria.documents = @target
|
|
150
|
+
criteria.paginate
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
protected
|
|
154
|
+
# Initializes each of the attributes in the hash.
|
|
155
|
+
def initialize_each(attributes)
|
|
156
|
+
@target = attributes ? attributes.collect do |attrs|
|
|
157
|
+
klass = attrs.klass
|
|
158
|
+
child = klass ? klass.instantiate(attrs) : @klass.instantiate(attrs)
|
|
159
|
+
child.parentize(@parent, @association_name)
|
|
160
|
+
child
|
|
161
|
+
end : []
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
class << self
|
|
165
|
+
|
|
166
|
+
# Preferred method of creating a new +EmbedsMany+ association. It will
|
|
167
|
+
# delegate to new.
|
|
168
|
+
#
|
|
169
|
+
# Options:
|
|
170
|
+
#
|
|
171
|
+
# document: The parent +Document+
|
|
172
|
+
# options: The association options
|
|
173
|
+
def instantiate(document, options)
|
|
174
|
+
new(document, options)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Returns the macro used to create the association.
|
|
178
|
+
def macro
|
|
179
|
+
:embeds_many
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Perform an update of the relationship of the parent and child. This
|
|
183
|
+
# is initialized by setting the has_many to the supplied +Enumerable+
|
|
184
|
+
# and setting up the parentization.
|
|
185
|
+
def update(children, parent, options)
|
|
186
|
+
parent.remove_attribute(options.name)
|
|
187
|
+
children.assimilate(parent, options)
|
|
188
|
+
instantiate(parent, options)
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc:
|
|
3
|
+
module Associations #:nodoc:
|
|
4
|
+
class EmbedsOne #:nodoc:
|
|
5
|
+
include Proxy
|
|
6
|
+
|
|
7
|
+
# Build a new object for the association.
|
|
8
|
+
def build(attrs = {}, type = nil)
|
|
9
|
+
@target = attrs.assimilate(@parent, @options, type); self
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Creates the new association by finding the attributes in
|
|
13
|
+
# the parent document with its name, and instantiating a
|
|
14
|
+
# new document for it.
|
|
15
|
+
#
|
|
16
|
+
# All method calls on this object will then be delegated
|
|
17
|
+
# to the internal document itself.
|
|
18
|
+
#
|
|
19
|
+
# Options:
|
|
20
|
+
#
|
|
21
|
+
# document: The parent +Document+
|
|
22
|
+
# attributes: The attributes of the target object.
|
|
23
|
+
# options: The association options.
|
|
24
|
+
#
|
|
25
|
+
# Returns:
|
|
26
|
+
#
|
|
27
|
+
# A new +HashOne+ association proxy.
|
|
28
|
+
def initialize(document, attrs, options)
|
|
29
|
+
@parent, @options = document, options
|
|
30
|
+
@target = attrs.assimilate(@parent, @options, attrs.klass)
|
|
31
|
+
extends(options)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Used for setting the association via a nested attributes setter on the
|
|
35
|
+
# parent +Document+. Called when using accepts_nested_attributes_for.
|
|
36
|
+
#
|
|
37
|
+
# Options:
|
|
38
|
+
#
|
|
39
|
+
# attributes: The attributes for the new association
|
|
40
|
+
#
|
|
41
|
+
# Returns:
|
|
42
|
+
#
|
|
43
|
+
# A new target document.
|
|
44
|
+
def nested_build(attributes)
|
|
45
|
+
build(attributes)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
class << self
|
|
49
|
+
# Preferred method of instantiating a new +EmbedsOne+, since nil values
|
|
50
|
+
# will be handled properly.
|
|
51
|
+
#
|
|
52
|
+
# Options:
|
|
53
|
+
#
|
|
54
|
+
# document: The parent +Document+
|
|
55
|
+
# options: The association options.
|
|
56
|
+
#
|
|
57
|
+
# Returns:
|
|
58
|
+
#
|
|
59
|
+
# A new +EmbedsOne+ association proxy.
|
|
60
|
+
def instantiate(document, options)
|
|
61
|
+
attributes = document.raw_attributes[options.name]
|
|
62
|
+
return nil if attributes.blank?
|
|
63
|
+
new(document, attributes, options)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Returns the macro used to create the association.
|
|
67
|
+
def macro
|
|
68
|
+
:embeds_one
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Perform an update of the relationship of the parent and child. This
|
|
72
|
+
# will assimilate the child +Document+ into the parent's object graph.
|
|
73
|
+
#
|
|
74
|
+
# Options:
|
|
75
|
+
#
|
|
76
|
+
# child: The child +Document+ or +Hash+.
|
|
77
|
+
# parent: The parent +Document+ to update.
|
|
78
|
+
# options: The association +Options+
|
|
79
|
+
#
|
|
80
|
+
# Example:
|
|
81
|
+
#
|
|
82
|
+
# <tt>EmbedsOne.update({:first_name => "Hank"}, person, options)</tt>
|
|
83
|
+
#
|
|
84
|
+
# Returns:
|
|
85
|
+
#
|
|
86
|
+
# A new +EmbedsOne+ association proxy.
|
|
87
|
+
def update(child, parent, options)
|
|
88
|
+
child.assimilate(parent, options)
|
|
89
|
+
instantiate(parent, options)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid #:nodoc:
|
|
3
|
+
module Associations #:nodoc:
|
|
4
|
+
class HasManyRelated #:nodoc:
|
|
5
|
+
include Proxy
|
|
6
|
+
|
|
7
|
+
# Appends the object to the +Array+, setting its parent in
|
|
8
|
+
# the process.
|
|
9
|
+
def <<(*objects)
|
|
10
|
+
load_target
|
|
11
|
+
objects.flatten.each do |object|
|
|
12
|
+
object.send("#{@foreign_key}=", @parent.id)
|
|
13
|
+
@target << object
|
|
14
|
+
object.save unless @parent.new_record?
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Builds a new Document and adds it to the association collection. The
|
|
19
|
+
# document created will be of the same class as the others in the
|
|
20
|
+
# association, and the attributes will be passed into the constructor.
|
|
21
|
+
#
|
|
22
|
+
# Returns the newly created object.
|
|
23
|
+
def build(attributes = {})
|
|
24
|
+
load_target
|
|
25
|
+
name = @parent.class.to_s.underscore
|
|
26
|
+
object = @klass.instantiate(attributes.merge(name => @parent))
|
|
27
|
+
@target << object
|
|
28
|
+
object
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Delegates to <<
|
|
32
|
+
def concat(*objects)
|
|
33
|
+
self << objects
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Creates a new Document and adds it to the association collection. The
|
|
37
|
+
# document created will be of the same class as the others in the
|
|
38
|
+
# association, and the attributes will be passed into the constructor and
|
|
39
|
+
# the new object will then be saved.
|
|
40
|
+
#
|
|
41
|
+
# Returns the newly created object.
|
|
42
|
+
def create(attributes)
|
|
43
|
+
object = build(attributes)
|
|
44
|
+
object.run_callbacks(:create) { object.save }; object
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Finds a document in this association.
|
|
48
|
+
# If an id is passed, will return the document for that id.
|
|
49
|
+
def find(*args)
|
|
50
|
+
args[1][:conditions].merge!(@foreign_key.to_sym => @parent.id) if args.size > 1
|
|
51
|
+
@klass.find(*args)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Initializing a related association only requires looking up the objects
|
|
55
|
+
# by their ids.
|
|
56
|
+
#
|
|
57
|
+
# Options:
|
|
58
|
+
#
|
|
59
|
+
# document: The +Document+ that contains the relationship.
|
|
60
|
+
# options: The association +Options+.
|
|
61
|
+
def initialize(document, options, target = nil)
|
|
62
|
+
@parent, @klass = document, options.klass
|
|
63
|
+
@foreign_key = options.foreign_key
|
|
64
|
+
@base = lambda { @klass.all(:conditions => { @foreign_key => document.id }) }
|
|
65
|
+
@target = target || @base.call
|
|
66
|
+
extends(options)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Override the default behavior to allow the criteria to get reset on
|
|
70
|
+
# each call into the association.
|
|
71
|
+
#
|
|
72
|
+
# Example:
|
|
73
|
+
#
|
|
74
|
+
# person.posts.where(:title => "New")
|
|
75
|
+
# person.posts # resets the criteria
|
|
76
|
+
#
|
|
77
|
+
# Returns:
|
|
78
|
+
#
|
|
79
|
+
# A Criteria object or Array.
|
|
80
|
+
def method_missing(name, *args, &block)
|
|
81
|
+
@target = @base.call unless @target.is_a?(Array)
|
|
82
|
+
@target.send(name, *args, &block)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Delegates to <<
|
|
86
|
+
def push(*objects)
|
|
87
|
+
self << objects
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
protected
|
|
91
|
+
# Load the target entries if the document is new.
|
|
92
|
+
def load_target
|
|
93
|
+
@target = @target.entries if @parent.new_record?
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
class << self
|
|
97
|
+
# Preferred method for creating the new +HasManyRelated+ association.
|
|
98
|
+
#
|
|
99
|
+
# Options:
|
|
100
|
+
#
|
|
101
|
+
# document: The +Document+ that contains the relationship.
|
|
102
|
+
# options: The association +Options+.
|
|
103
|
+
def instantiate(document, options, target = nil)
|
|
104
|
+
new(document, options, target)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Returns the macro used to create the association.
|
|
108
|
+
def macro
|
|
109
|
+
:has_many_related
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Perform an update of the relationship of the parent and child. This
|
|
113
|
+
# will assimilate the child +Document+ into the parent's object graph.
|
|
114
|
+
#
|
|
115
|
+
# Options:
|
|
116
|
+
#
|
|
117
|
+
# related: The related object
|
|
118
|
+
# parent: The parent +Document+ to update.
|
|
119
|
+
# options: The association +Options+
|
|
120
|
+
#
|
|
121
|
+
# Example:
|
|
122
|
+
#
|
|
123
|
+
# <tt>RelatesToOne.update(game, person, options)</tt>
|
|
124
|
+
def update(target, document, options)
|
|
125
|
+
name = document.class.to_s.underscore
|
|
126
|
+
target.each { |child| child.send("#{name}=", document) }
|
|
127
|
+
instantiate(document, options, target)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|