mongoid 2.0.0.beta.20 → 2.0.0.rc.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +8 -0
- data/Rakefile +51 -0
- data/lib/config/locales/nl.yml +39 -0
- data/lib/config/locales/ro.yml +1 -1
- data/lib/mongoid.rb +17 -17
- data/lib/mongoid/atomicity.rb +54 -22
- data/lib/mongoid/attributes.rb +145 -125
- data/lib/mongoid/callbacks.rb +7 -2
- data/lib/mongoid/collection.rb +49 -32
- data/lib/mongoid/collections.rb +0 -1
- data/lib/mongoid/components.rb +34 -29
- data/lib/mongoid/config.rb +207 -193
- data/lib/mongoid/config/database.rb +167 -0
- data/lib/mongoid/contexts.rb +2 -5
- data/lib/mongoid/contexts/enumerable.rb +30 -4
- data/lib/mongoid/contexts/ids.rb +2 -2
- data/lib/mongoid/contexts/mongo.rb +30 -5
- data/lib/mongoid/copyable.rb +44 -0
- data/lib/mongoid/criteria.rb +110 -56
- data/lib/mongoid/criterion/creational.rb +34 -0
- data/lib/mongoid/criterion/destructive.rb +37 -0
- data/lib/mongoid/criterion/exclusion.rb +3 -1
- data/lib/mongoid/criterion/inclusion.rb +59 -64
- data/lib/mongoid/criterion/inspection.rb +22 -0
- data/lib/mongoid/criterion/optional.rb +42 -54
- data/lib/mongoid/criterion/selector.rb +9 -0
- data/lib/mongoid/default_scope.rb +28 -0
- data/lib/mongoid/deprecation.rb +5 -5
- data/lib/mongoid/dirty.rb +4 -5
- data/lib/mongoid/document.rb +161 -114
- data/lib/mongoid/extensions.rb +7 -11
- data/lib/mongoid/extensions/array/parentization.rb +2 -2
- data/lib/mongoid/extensions/date/conversions.rb +1 -1
- data/lib/mongoid/extensions/hash/conversions.rb +0 -23
- data/lib/mongoid/extensions/nil/collectionization.rb +12 -0
- data/lib/mongoid/extensions/object/reflections.rb +17 -0
- data/lib/mongoid/extensions/object/yoda.rb +27 -0
- data/lib/mongoid/extensions/string/conversions.rb +23 -4
- data/lib/mongoid/extensions/time_conversions.rb +4 -4
- data/lib/mongoid/field.rb +30 -19
- data/lib/mongoid/fields.rb +15 -5
- data/lib/mongoid/finders.rb +19 -11
- data/lib/mongoid/hierarchy.rb +34 -28
- data/lib/mongoid/identity.rb +62 -20
- data/lib/mongoid/inspection.rb +58 -0
- data/lib/mongoid/matchers.rb +20 -0
- data/lib/mongoid/multi_database.rb +11 -0
- data/lib/mongoid/nested_attributes.rb +41 -0
- data/lib/mongoid/paranoia.rb +3 -4
- data/lib/mongoid/paths.rb +1 -1
- data/lib/mongoid/persistence.rb +89 -90
- data/lib/mongoid/persistence/command.rb +20 -4
- data/lib/mongoid/persistence/insert.rb +13 -11
- data/lib/mongoid/persistence/insert_embedded.rb +8 -6
- data/lib/mongoid/persistence/remove.rb +6 -4
- data/lib/mongoid/persistence/remove_all.rb +6 -4
- data/lib/mongoid/persistence/remove_embedded.rb +8 -6
- data/lib/mongoid/persistence/update.rb +12 -10
- data/lib/mongoid/railtie.rb +2 -2
- data/lib/mongoid/railties/database.rake +10 -9
- data/lib/mongoid/relations.rb +104 -0
- data/lib/mongoid/relations/accessors.rb +154 -0
- data/lib/mongoid/relations/auto_save.rb +34 -0
- data/lib/mongoid/relations/binding.rb +24 -0
- data/lib/mongoid/relations/bindings.rb +9 -0
- data/lib/mongoid/relations/bindings/embedded/in.rb +77 -0
- data/lib/mongoid/relations/bindings/embedded/many.rb +93 -0
- data/lib/mongoid/relations/bindings/embedded/one.rb +65 -0
- data/lib/mongoid/relations/bindings/referenced/in.rb +78 -0
- data/lib/mongoid/relations/bindings/referenced/many.rb +93 -0
- data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +94 -0
- data/lib/mongoid/relations/bindings/referenced/one.rb +63 -0
- data/lib/mongoid/relations/builder.rb +41 -0
- data/lib/mongoid/relations/builders.rb +79 -0
- data/lib/mongoid/relations/builders/embedded/in.rb +25 -0
- data/lib/mongoid/relations/builders/embedded/many.rb +32 -0
- data/lib/mongoid/relations/builders/embedded/one.rb +26 -0
- data/lib/mongoid/relations/builders/nested_attributes/many.rb +116 -0
- data/lib/mongoid/relations/builders/nested_attributes/one.rb +135 -0
- data/lib/mongoid/relations/builders/referenced/in.rb +32 -0
- data/lib/mongoid/relations/builders/referenced/many.rb +26 -0
- data/lib/mongoid/relations/builders/referenced/many_to_many.rb +29 -0
- data/lib/mongoid/relations/builders/referenced/one.rb +30 -0
- data/lib/mongoid/relations/cascading.rb +55 -0
- data/lib/mongoid/relations/cascading/delete.rb +19 -0
- data/lib/mongoid/relations/cascading/destroy.rb +19 -0
- data/lib/mongoid/relations/cascading/nullify.rb +18 -0
- data/lib/mongoid/relations/cascading/strategy.rb +26 -0
- data/lib/mongoid/relations/cyclic.rb +97 -0
- data/lib/mongoid/relations/embedded/in.rb +172 -0
- data/lib/mongoid/relations/embedded/many.rb +450 -0
- data/lib/mongoid/relations/embedded/one.rb +169 -0
- data/lib/mongoid/relations/macros.rb +302 -0
- data/lib/mongoid/relations/many.rb +185 -0
- data/lib/mongoid/relations/metadata.rb +529 -0
- data/lib/mongoid/relations/nested_builder.rb +52 -0
- data/lib/mongoid/relations/one.rb +29 -0
- data/lib/mongoid/relations/polymorphic.rb +54 -0
- data/lib/mongoid/relations/proxy.rb +122 -0
- data/lib/mongoid/relations/referenced/in.rb +214 -0
- data/lib/mongoid/relations/referenced/many.rb +358 -0
- data/lib/mongoid/relations/referenced/many_to_many.rb +379 -0
- data/lib/mongoid/relations/referenced/one.rb +204 -0
- data/lib/mongoid/relations/reflections.rb +45 -0
- data/lib/mongoid/safe.rb +11 -1
- data/lib/mongoid/safety.rb +122 -97
- data/lib/mongoid/scope.rb +14 -9
- data/lib/mongoid/state.rb +37 -3
- data/lib/mongoid/timestamps.rb +11 -0
- data/lib/mongoid/validations.rb +42 -3
- data/lib/mongoid/validations/associated.rb +8 -5
- data/lib/mongoid/validations/uniqueness.rb +23 -2
- data/lib/mongoid/version.rb +1 -1
- data/lib/mongoid/versioning.rb +25 -16
- data/lib/rails/generators/mongoid/model/templates/model.rb +3 -1
- metadata +95 -80
- data/lib/mongoid/associations.rb +0 -364
- data/lib/mongoid/associations/embedded_in.rb +0 -74
- data/lib/mongoid/associations/embeds_many.rb +0 -299
- data/lib/mongoid/associations/embeds_one.rb +0 -111
- data/lib/mongoid/associations/foreign_key.rb +0 -35
- data/lib/mongoid/associations/meta_data.rb +0 -38
- data/lib/mongoid/associations/options.rb +0 -78
- data/lib/mongoid/associations/proxy.rb +0 -60
- data/lib/mongoid/associations/referenced_in.rb +0 -70
- data/lib/mongoid/associations/references_many.rb +0 -254
- data/lib/mongoid/associations/references_many_as_array.rb +0 -128
- data/lib/mongoid/associations/references_one.rb +0 -104
- data/lib/mongoid/extensions/array/accessors.rb +0 -17
- data/lib/mongoid/extensions/array/assimilation.rb +0 -26
- data/lib/mongoid/extensions/hash/accessors.rb +0 -42
- data/lib/mongoid/extensions/hash/assimilation.rb +0 -40
- data/lib/mongoid/extensions/nil/assimilation.rb +0 -17
- data/lib/mongoid/memoization.rb +0 -33
data/README.rdoc
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
= PLEASE READ (03 JAN 2011)
|
2
|
+
|
3
|
+
USERS CURRENTLY POINTED AT master, PLEASE MOVE TO safe_master UNTIL
|
4
|
+
FURTHER NOTICE.
|
5
|
+
|
1
6
|
= Overview
|
2
7
|
|
3
8
|
== About Mongoid
|
@@ -18,6 +23,9 @@ Mongoid is developed against Ruby 1.8.7, 1.9.1, 1.9.2, and REE.
|
|
18
23
|
Please see the new Mongoid website for up-to-date documentation:
|
19
24
|
{mongoid.org}[http://mongoid.org]
|
20
25
|
|
26
|
+
= Donating
|
27
|
+
* {Support Mongoid at Pledgie}[http://www.pledgie.com/campaigns/7757]
|
28
|
+
|
21
29
|
= License
|
22
30
|
|
23
31
|
Copyright (c) 2009, 2010 Durran Jordan
|
data/Rakefile
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require "bundler"
|
2
|
+
Bundler.setup
|
3
|
+
|
4
|
+
require "rake"
|
5
|
+
require "rake/rdoctask"
|
6
|
+
require "rspec"
|
7
|
+
require "rspec/core/rake_task"
|
8
|
+
|
9
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
10
|
+
require "mongoid/version"
|
11
|
+
|
12
|
+
task :gem => :build
|
13
|
+
task :build do
|
14
|
+
system "gem build mongoid.gemspec"
|
15
|
+
end
|
16
|
+
|
17
|
+
task :install => :build do
|
18
|
+
system "sudo gem install mongoid-#{Mongoid::VERSION}.gem"
|
19
|
+
end
|
20
|
+
|
21
|
+
task :release => :build do
|
22
|
+
system "git tag -a #{Mongoid::VERSION} -m 'Tagging #{Mongoid::VERSION}'"
|
23
|
+
system "git push --tags"
|
24
|
+
system "gem push mongoid-#{Mongoid::VERSION}.gem"
|
25
|
+
end
|
26
|
+
|
27
|
+
Rspec::Core::RakeTask.new(:spec) do |spec|
|
28
|
+
spec.pattern = "spec/**/*_spec.rb"
|
29
|
+
end
|
30
|
+
|
31
|
+
Rspec::Core::RakeTask.new("spec:unit") do |spec|
|
32
|
+
spec.pattern = "spec/unit/**/*_spec.rb"
|
33
|
+
end
|
34
|
+
|
35
|
+
Rspec::Core::RakeTask.new("spec:integration") do |spec|
|
36
|
+
spec.pattern = "spec/integration/**/*_spec.rb"
|
37
|
+
end
|
38
|
+
|
39
|
+
Rspec::Core::RakeTask.new('spec:progress') do |spec|
|
40
|
+
spec.rspec_opts = %w(--format progress)
|
41
|
+
spec.pattern = "spec/**/*_spec.rb"
|
42
|
+
end
|
43
|
+
|
44
|
+
Rake::RDocTask.new do |rdoc|
|
45
|
+
rdoc.rdoc_dir = "rdoc"
|
46
|
+
rdoc.title = "mongoid #{Mongoid::VERSION}"
|
47
|
+
rdoc.rdoc_files.include("README*")
|
48
|
+
rdoc.rdoc_files.include("lib/**/*.rb")
|
49
|
+
end
|
50
|
+
|
51
|
+
task :default => :spec
|
@@ -0,0 +1,39 @@
|
|
1
|
+
nl:
|
2
|
+
activemodel:
|
3
|
+
errors:
|
4
|
+
messages:
|
5
|
+
taken: al in gebruik
|
6
|
+
|
7
|
+
mongoid:
|
8
|
+
errors:
|
9
|
+
messages:
|
10
|
+
document_not_found:
|
11
|
+
Document niet gevonden voor class %{klass} met de id(s) %{identifiers}.
|
12
|
+
invalid_database:
|
13
|
+
Database moet een Mongo::DB zijn, niet een %{name}.
|
14
|
+
invalid_type:
|
15
|
+
Veld was gedefinieerd als een %{klass}, maar ontvangen als %{other} met
|
16
|
+
de waarde %{value}.
|
17
|
+
unsupported_version:
|
18
|
+
MongoDB %{version} wordt niet ondersteund, upgrade naar versie %{mongo_version}.
|
19
|
+
validations:
|
20
|
+
Gefaalde validatie - %{errors}.
|
21
|
+
invalid_collection:
|
22
|
+
Toegang tot de collectie voor %{klass} is niet toegestaan aangezien het
|
23
|
+
een embedded document is, benader de collectie van een root document.
|
24
|
+
invalid_field:
|
25
|
+
Het is niet toegestaan om een veld genaamd %{name} te definiëren.
|
26
|
+
Definieer geen velden die conflicteren met de Mongoid interne attributen of methode namen.
|
27
|
+
Gerbuik Document#instance_methods om welke namen dit gaat.
|
28
|
+
too_many_nested_attribute_records:
|
29
|
+
Het accepteren van nested attributes voor %{association} is gelimiteerd tot %{limit} records.
|
30
|
+
embedded_in_must_have_inverse_of:
|
31
|
+
Opties voor embedded_in association moet gebruik maken van de inverse_of optie.
|
32
|
+
dependent_only_references_one_or_many:
|
33
|
+
De dependent => destroy|delete optie die was meegegeven is alleen geldig
|
34
|
+
op references_one en references_many associations.
|
35
|
+
association_cant_have_inverse_of:
|
36
|
+
Het definieren van een inverse_of op deze association is niet toegestaan. Gebruik
|
37
|
+
alleen deze optie met embedded_in en references_many as array.
|
38
|
+
calling_document_find_with_nil_is_invalid:
|
39
|
+
Het is niet toegestaan om Document#find aan te roepen met de waarde nil.
|
data/lib/config/locales/ro.yml
CHANGED
data/lib/mongoid.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
|
2
3
|
# Copyright (c) 2009, 2010 Durran Jordan
|
3
4
|
#
|
4
5
|
# Permission is hereby granted, free of charge, to any person obtaining
|
@@ -19,9 +20,7 @@
|
|
19
20
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
21
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
22
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
-
|
23
23
|
require "delegate"
|
24
|
-
require "singleton"
|
25
24
|
require "time"
|
26
25
|
require "ostruct"
|
27
26
|
require "active_support/core_ext"
|
@@ -43,7 +42,6 @@ require "mongo"
|
|
43
42
|
require "mongoid/errors"
|
44
43
|
require "mongoid/extensions"
|
45
44
|
require "mongoid/safe"
|
46
|
-
require "mongoid/associations"
|
47
45
|
require "mongoid/atomicity"
|
48
46
|
require "mongoid/attributes"
|
49
47
|
require "mongoid/callbacks"
|
@@ -51,9 +49,11 @@ require "mongoid/collection"
|
|
51
49
|
require "mongoid/collections"
|
52
50
|
require "mongoid/config"
|
53
51
|
require "mongoid/contexts"
|
52
|
+
require "mongoid/copyable"
|
54
53
|
require "mongoid/criteria"
|
55
54
|
require "mongoid/cursor"
|
56
55
|
require "mongoid/deprecation"
|
56
|
+
require "mongoid/default_scope"
|
57
57
|
require "mongoid/dirty"
|
58
58
|
require "mongoid/extras"
|
59
59
|
require "mongoid/factory"
|
@@ -63,17 +63,20 @@ require "mongoid/finders"
|
|
63
63
|
require "mongoid/hierarchy"
|
64
64
|
require "mongoid/identity"
|
65
65
|
require "mongoid/indexes"
|
66
|
+
require "mongoid/inspection"
|
66
67
|
require "mongoid/javascript"
|
67
68
|
require "mongoid/json"
|
68
69
|
require "mongoid/keys"
|
69
70
|
require "mongoid/logger"
|
70
71
|
require "mongoid/matchers"
|
71
|
-
require "mongoid/memoization"
|
72
72
|
require "mongoid/modifiers"
|
73
73
|
require "mongoid/multi_parameter_attributes"
|
74
|
+
require "mongoid/multi_database"
|
74
75
|
require "mongoid/named_scope"
|
76
|
+
require "mongoid/nested_attributes"
|
75
77
|
require "mongoid/paths"
|
76
78
|
require "mongoid/persistence"
|
79
|
+
require "mongoid/relations"
|
77
80
|
require "mongoid/safety"
|
78
81
|
require "mongoid/scope"
|
79
82
|
require "mongoid/state"
|
@@ -100,7 +103,7 @@ module Mongoid #:nodoc
|
|
100
103
|
|
101
104
|
# Sets the Mongoid configuration options. Best used by passing a block.
|
102
105
|
#
|
103
|
-
#
|
106
|
+
# @example Set up configuration options.
|
104
107
|
#
|
105
108
|
# Mongoid.configure do |config|
|
106
109
|
# name = "mongoid_test"
|
@@ -113,33 +116,30 @@ module Mongoid #:nodoc
|
|
113
116
|
# ]
|
114
117
|
# end
|
115
118
|
#
|
116
|
-
#
|
117
|
-
#
|
118
|
-
# The Mongoid +Config+ singleton instance.
|
119
|
+
# @return [ Config ] The configuration obejct.
|
119
120
|
def configure
|
120
|
-
config = Mongoid::Config
|
121
|
+
config = Mongoid::Config
|
121
122
|
block_given? ? yield(config) : config
|
122
123
|
end
|
124
|
+
alias :config :configure
|
123
125
|
|
124
126
|
# Easy convenience method for generating an alert from the
|
125
127
|
# deprecation module.
|
126
128
|
#
|
127
|
-
#
|
129
|
+
# @example Alert a deprecation.
|
130
|
+
# Mongoid.deprecate("Method no longer used")
|
128
131
|
#
|
129
|
-
#
|
132
|
+
# @param [ String ] message The message to print.
|
130
133
|
def deprecate(message)
|
131
|
-
Mongoid::Deprecation.
|
134
|
+
Mongoid::Deprecation.alert(message)
|
132
135
|
end
|
133
|
-
|
134
|
-
alias :config :configure
|
135
136
|
end
|
136
137
|
|
137
138
|
# Take all the public instance methods from the Config singleton and allow
|
138
139
|
# them to be accessed through the Mongoid module directly.
|
139
140
|
#
|
140
|
-
#
|
141
|
-
#
|
142
|
-
# <tt>Mongoid.database = Mongo::Connection.new.db("test")</tt>
|
141
|
+
# @example Delegate the configuration methods.
|
142
|
+
# Mongoid.database = Mongo::Connection.new.db("test")
|
143
143
|
Mongoid::Config.public_instance_methods(false).each do |name|
|
144
144
|
(class << self; self; end).class_eval <<-EOT
|
145
145
|
def #{name}(*args)
|
data/lib/mongoid/atomicity.rb
CHANGED
@@ -1,46 +1,52 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module Mongoid #:nodoc:
|
3
|
-
|
3
|
+
|
4
|
+
# This module contains the logic for supporting atomic operations against the
|
5
|
+
# database.
|
6
|
+
#
|
7
|
+
# @todo Durran: Refactor class out into separate objects for each type of
|
8
|
+
# update.
|
9
|
+
module Atomicity
|
4
10
|
extend ActiveSupport::Concern
|
5
11
|
|
6
12
|
# Get all the atomic updates that need to happen for the current
|
7
13
|
# +Document+. This includes all changes that need to happen in the
|
8
14
|
# entire hierarchy that exists below where the save call was made.
|
9
15
|
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
16
|
+
# @note
|
17
|
+
# MongoDB does not allow "conflicting modifications" to be
|
18
|
+
# performed in a single operation. Conflicting modifications are
|
19
|
+
# detected by the 'haveConflictingMod' function in MongoDB.
|
20
|
+
# Examination of the code suggests that two modifications (a $set
|
21
|
+
# and a $pushAll, for example) conflict if:
|
22
|
+
# (1) the key paths being modified are equal.
|
23
|
+
# (2) one key path is a prefix of the other.
|
24
|
+
# So a $set of 'addresses.0.street' will conflict with a $pushAll
|
25
|
+
# to 'addresses', and we will need to split our update into two
|
26
|
+
# pieces. We do not, however, attempt to match MongoDB's logic
|
27
|
+
# exactly. Instead, we assume that two updates conflict if the
|
28
|
+
# first component of the two key paths matches.
|
13
29
|
#
|
14
|
-
#
|
30
|
+
# @example Get the updates that need to occur.
|
31
|
+
# person._updates
|
15
32
|
#
|
16
|
-
#
|
33
|
+
# @return [ Hash ] The updates and their modifiers.
|
17
34
|
def _updates
|
18
35
|
processed = {}
|
19
|
-
|
36
|
+
|
20
37
|
_children.inject({ "$set" => _sets, "$pushAll" => {}, :other => {} }) do |updates, child|
|
21
38
|
changes = child._sets
|
22
39
|
updates["$set"].update(changes)
|
23
40
|
unless changes.empty?
|
24
41
|
processed[child._conficting_modification_key] = true
|
25
42
|
end
|
26
|
-
|
27
|
-
# MongoDB does not allow "conflicting modifications" to be
|
28
|
-
# performed in a single operation. Conflicting modifications are
|
29
|
-
# detected by the 'haveConflictingMod' function in MongoDB.
|
30
|
-
# Examination of the code suggests that two modifications (a $set
|
31
|
-
# and a $pushAll, for example) conflict if (1) the key paths being
|
32
|
-
# modified are equal or (2) one key path is a prefix of the other.
|
33
|
-
# So a $set of 'addresses.0.street' will conflict with a $pushAll
|
34
|
-
# to 'addresses', and we will need to split our update into two
|
35
|
-
# pieces. We do not, however, attempt to match MongoDB's logic
|
36
|
-
# exactly. Instead, we assume that two updates conflict if the
|
37
|
-
# first component of the two key paths matches.
|
43
|
+
|
38
44
|
if processed.has_key?(child._conficting_modification_key)
|
39
45
|
target = :other
|
40
46
|
else
|
41
47
|
target = "$pushAll"
|
42
48
|
end
|
43
|
-
|
49
|
+
|
44
50
|
child._pushes.each do |attr, val|
|
45
51
|
if updates[target].has_key?(attr)
|
46
52
|
updates[target][attr] << val
|
@@ -55,24 +61,50 @@ module Mongoid #:nodoc:
|
|
55
61
|
end
|
56
62
|
|
57
63
|
protected
|
64
|
+
|
58
65
|
# Get the key used to check for conflicting modifications. For now, we
|
59
66
|
# just use the first component of _path, and discard the first period
|
60
67
|
# and everything that follows.
|
68
|
+
#
|
69
|
+
# @example Get the key.
|
70
|
+
# person._conflicting_modification_key
|
71
|
+
#
|
72
|
+
# @return [ String ] The conflicting key.
|
61
73
|
def _conficting_modification_key
|
62
74
|
_path.sub(/\..*/, '')
|
63
75
|
end
|
64
76
|
|
65
77
|
# Get all the push attributes that need to occur.
|
78
|
+
#
|
79
|
+
# @example Get the pushes.
|
80
|
+
# person._pushes
|
81
|
+
#
|
82
|
+
# @return [ Hash ] The $pushAll operations.
|
66
83
|
def _pushes
|
67
|
-
|
84
|
+
pushable? ? { _path => to_hash } : {}
|
85
|
+
end
|
86
|
+
|
87
|
+
# Determine if the document can be pushed.
|
88
|
+
#
|
89
|
+
# @example Is this pushable?
|
90
|
+
# person.pushable?
|
91
|
+
#
|
92
|
+
# @return [ true, false ] Is the document new and embedded?
|
93
|
+
def pushable?
|
94
|
+
new_record? && embedded_many? && _parent.persisted?
|
68
95
|
end
|
69
96
|
|
70
97
|
# Get all the attributes that need to be set.
|
98
|
+
#
|
99
|
+
# @example Get the sets.
|
100
|
+
# person._sets
|
101
|
+
#
|
102
|
+
# @return [ Hash ] The $set operations.
|
71
103
|
def _sets
|
72
104
|
if changed? && !new_record?
|
73
105
|
setters
|
74
106
|
else
|
75
|
-
embedded_one? && new_record? ? { _path =>
|
107
|
+
embedded_one? && new_record? ? { _path => to_hash } : {}
|
76
108
|
end
|
77
109
|
end
|
78
110
|
end
|
data/lib/mongoid/attributes.rb
CHANGED
@@ -1,23 +1,75 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module Mongoid #:nodoc:
|
3
|
+
|
4
|
+
# This module contains the logic for handling the internal attributes hash,
|
5
|
+
# and how to get and set values.
|
3
6
|
module Attributes
|
4
|
-
|
7
|
+
|
8
|
+
# Returns the object type. This corresponds to the name of the class that
|
9
|
+
# this document is, which is used in determining the class to
|
10
|
+
# instantiate in various cases.
|
11
|
+
#
|
12
|
+
# @example Get the type.
|
13
|
+
# person._type
|
14
|
+
#
|
15
|
+
# @return [ String ] The name of the class the document is.
|
16
|
+
def _type
|
17
|
+
@attributes["_type"]
|
18
|
+
end
|
19
|
+
|
20
|
+
# Set the type of the document. This should be the name of the class.
|
21
|
+
#
|
22
|
+
# @example Set the type
|
23
|
+
# person._type = "Person"
|
24
|
+
#
|
25
|
+
# @param [ String ] new_type The name of the class.
|
26
|
+
#
|
27
|
+
# @return [ String ] the new type.
|
28
|
+
def _type=(new_type)
|
29
|
+
@attributes["_type"] = new_type
|
30
|
+
end
|
31
|
+
|
32
|
+
# Determine if an attribute is present.
|
33
|
+
#
|
34
|
+
# @example Is the attribute present?
|
35
|
+
# person.attribute_present?("title")
|
36
|
+
#
|
37
|
+
# @param [ String, Symbol ] name The name of the attribute.
|
38
|
+
#
|
39
|
+
# @return [ true, false ] True if present, false if not.
|
40
|
+
def attribute_present?(name)
|
41
|
+
!read_attribute(name).blank?
|
42
|
+
end
|
5
43
|
|
6
44
|
# Get the id associated with this object. This will pull the _id value out
|
7
|
-
# of the attributes
|
45
|
+
# of the attributes.
|
46
|
+
#
|
47
|
+
# @example Get the id.
|
48
|
+
# person.id
|
49
|
+
#
|
50
|
+
# @return [ BSON::ObjectId, String ] The id of the document.
|
8
51
|
def id
|
9
52
|
@attributes["_id"]
|
10
53
|
end
|
54
|
+
alias :_id :id
|
11
55
|
|
12
|
-
# Set the id of the
|
56
|
+
# Set the id of the document to a new one.
|
57
|
+
#
|
58
|
+
# @example Set the id.
|
59
|
+
# person.id = BSON::ObjectId.new
|
60
|
+
#
|
61
|
+
# @param [ BSON::ObjectId, String ] new_id The new id.
|
62
|
+
#
|
63
|
+
# @return [ BSON::ObjectId, String ] The new id.
|
13
64
|
def id=(new_id)
|
14
65
|
@attributes["_id"] = new_id
|
15
66
|
end
|
16
|
-
|
17
|
-
alias :_id :id
|
18
67
|
alias :_id= :id=
|
19
68
|
|
20
69
|
# Used for allowing accessor methods for dynamic attributes.
|
70
|
+
#
|
71
|
+
# @param [ String, Symbol ] name The name of the method.
|
72
|
+
# @param [ Array ] *args The arguments to the method.
|
21
73
|
def method_missing(name, *args)
|
22
74
|
attr = name.to_s
|
23
75
|
return super unless @attributes.has_key?(attr.reader)
|
@@ -29,44 +81,42 @@ module Mongoid #:nodoc:
|
|
29
81
|
end
|
30
82
|
end
|
31
83
|
|
32
|
-
# Override respond_to? so it responds properly for dynamic attributes
|
33
|
-
def respond_to?(*args)
|
34
|
-
(Mongoid.allow_dynamic_fields && @attributes && @attributes.has_key?(args.first.to_s)) || super
|
35
|
-
end
|
36
|
-
|
37
84
|
# Process the provided attributes casting them to their proper values if a
|
38
|
-
# field exists for them on the
|
85
|
+
# field exists for them on the document. This will be limited to only the
|
39
86
|
# attributes provided in the suppied +Hash+ so that no extra nil values get
|
40
87
|
# put into the document's attributes.
|
88
|
+
#
|
89
|
+
# @example Process the attributes.
|
90
|
+
# person.process(:title => "sir", :age => 40)
|
91
|
+
#
|
92
|
+
# @param [ Hash ] attrs The attributes to set.
|
41
93
|
def process(attrs = nil)
|
94
|
+
pending = {}
|
42
95
|
sanitize_for_mass_assignment(attrs || {}).each_pair do |key, value|
|
43
96
|
if set_allowed?(key)
|
44
97
|
write_attribute(key, value)
|
45
98
|
else
|
46
|
-
|
47
|
-
|
48
|
-
association.nested_build(value)
|
49
|
-
else
|
50
|
-
send("build_#{key}", value)
|
51
|
-
end
|
52
|
-
else
|
53
|
-
send("#{key}=", value)
|
54
|
-
end
|
99
|
+
pending[key.to_s] = value and next if relations.has_key?(key.to_s)
|
100
|
+
send("#{key}=", value)
|
55
101
|
end
|
56
102
|
end
|
103
|
+
yield self if block_given?
|
104
|
+
process_relations(pending)
|
57
105
|
setup_modifications
|
58
106
|
end
|
59
107
|
|
60
|
-
# Read a value from the
|
108
|
+
# Read a value from the document attributes. If the value does not exist
|
61
109
|
# it will return nil.
|
62
110
|
#
|
63
|
-
#
|
111
|
+
# @example Read an attribute.
|
112
|
+
# person.read_attribute(:title)
|
64
113
|
#
|
65
|
-
#
|
114
|
+
# @example Read an attribute (alternate syntax.)
|
115
|
+
# person[:title]
|
66
116
|
#
|
67
|
-
#
|
117
|
+
# @param [ String, Symbol ] name The name of the attribute to get.
|
68
118
|
#
|
69
|
-
#
|
119
|
+
# @return [ Object ] The value of the attribute.
|
70
120
|
def read_attribute(name)
|
71
121
|
access = name.to_s
|
72
122
|
value = @attributes[access]
|
@@ -78,93 +128,75 @@ module Mongoid #:nodoc:
|
|
78
128
|
# Remove a value from the +Document+ attributes. If the value does not exist
|
79
129
|
# it will fail gracefully.
|
80
130
|
#
|
81
|
-
#
|
82
|
-
#
|
83
|
-
# name: The name of the attribute to remove.
|
131
|
+
# @example Remove the attribute.
|
132
|
+
# person.remove_attribute(:title)
|
84
133
|
#
|
85
|
-
#
|
86
|
-
#
|
87
|
-
# <tt>person.remove_attribute(:title)</tt>
|
134
|
+
# @param [ String, Symbol ] name The name of the attribute to remove.
|
88
135
|
def remove_attribute(name)
|
89
136
|
access = name.to_s
|
90
137
|
modify(access, @attributes.delete(name.to_s), nil)
|
91
138
|
end
|
92
139
|
|
93
|
-
#
|
140
|
+
# Override respond_to? so it responds properly for dynamic attributes.
|
94
141
|
#
|
95
|
-
#
|
142
|
+
# @example Does this object respond to the method?
|
143
|
+
# person.respond_to?(:title)
|
96
144
|
#
|
97
|
-
#
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
# instantiate in various cases.
|
106
|
-
def _type
|
107
|
-
@attributes["_type"]
|
108
|
-
end
|
109
|
-
|
110
|
-
# Set the type of the +Document+. This should be the name of the class.
|
111
|
-
def _type=(new_type)
|
112
|
-
@attributes["_type"] = new_type
|
145
|
+
# @param [ Array ] *args The name of the method.
|
146
|
+
#
|
147
|
+
# @return [ true, false ] True if it does, false if not.
|
148
|
+
def respond_to?(*args)
|
149
|
+
(Mongoid.allow_dynamic_fields &&
|
150
|
+
@attributes &&
|
151
|
+
@attributes.has_key?(args.first.to_s)
|
152
|
+
) || super
|
113
153
|
end
|
114
154
|
|
115
|
-
# Write a single attribute to the
|
155
|
+
# Write a single attribute to the document attribute hash. This will
|
116
156
|
# also fire the before and after update callbacks, and perform any
|
117
157
|
# necessary typecasting.
|
118
158
|
#
|
119
|
-
#
|
120
|
-
#
|
121
|
-
# name: The name of the attribute to update.
|
122
|
-
# value: The value to set for the attribute.
|
123
|
-
#
|
124
|
-
# Example:
|
159
|
+
# @example Write the attribute.
|
160
|
+
# person.write_attribute(:title, "Mr.")
|
125
161
|
#
|
126
|
-
#
|
162
|
+
# @example Write the attribute (alternate syntax.)
|
163
|
+
# person[:title] = "Mr."
|
127
164
|
#
|
128
|
-
#
|
129
|
-
#
|
165
|
+
# @param [ String, Symbol ] name The name of the attribute to update.
|
166
|
+
# @param [ Object ] value The value to set for the attribute.
|
130
167
|
def write_attribute(name, value)
|
131
168
|
access = name.to_s
|
132
169
|
modify(access, @attributes[access], typed_value_for(access, value))
|
133
|
-
notify if !id.blank? && new_record?
|
134
170
|
end
|
135
171
|
alias :[]= :write_attribute
|
136
172
|
|
137
|
-
# Writes the supplied attributes
|
173
|
+
# Writes the supplied attributes hash to the document. This will only
|
138
174
|
# overwrite existing attributes if they are present in the new +Hash+, all
|
139
175
|
# others will be preserved.
|
140
176
|
#
|
141
|
-
#
|
177
|
+
# @example Write the attributes.
|
178
|
+
# person.write_attributes(:title => "Mr.")
|
142
179
|
#
|
143
|
-
#
|
180
|
+
# @example Write the attributes (alternate syntax.)
|
181
|
+
# person.attributes = { :title => "Mr." }
|
144
182
|
#
|
145
|
-
#
|
146
|
-
#
|
147
|
-
# <tt>person.write_attributes(:title => "Mr.")</tt>
|
148
|
-
#
|
149
|
-
# This will also cause the observing +Document+ to notify it's parent if
|
150
|
-
# there is any.
|
183
|
+
# @param [ Hash ] attrs The new attributes to set.
|
151
184
|
def write_attributes(attrs = nil)
|
152
185
|
process(attrs || {})
|
153
|
-
|
154
|
-
|
155
|
-
identify; notify
|
186
|
+
if new_record? && id.blank?
|
187
|
+
identify
|
156
188
|
end
|
157
189
|
end
|
158
190
|
alias :attributes= :write_attributes
|
159
191
|
|
160
192
|
protected
|
161
193
|
|
162
|
-
#
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
#
|
194
|
+
# Get the default values for the attributes.
|
195
|
+
#
|
196
|
+
# @example Get the defaults.
|
197
|
+
# person.default_attributes
|
198
|
+
#
|
199
|
+
# @return [ Hash ] The default values for each field.
|
168
200
|
def default_attributes
|
169
201
|
default_values = defaults
|
170
202
|
default_values.each_pair do |key, val|
|
@@ -173,59 +205,47 @@ module Mongoid #:nodoc:
|
|
173
205
|
default_values || {}
|
174
206
|
end
|
175
207
|
|
176
|
-
#
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
#
|
182
|
-
#
|
183
|
-
def
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
208
|
+
# Process all the pending relations that needed to wait until ids were set
|
209
|
+
# to fire off.
|
210
|
+
#
|
211
|
+
# @example Process the relations.
|
212
|
+
# document.process_relations({ "addressable" => person })
|
213
|
+
#
|
214
|
+
# @param [ Hash ] pending The pending relation values.
|
215
|
+
def process_relations(pending)
|
216
|
+
pending.each_pair do |name, value|
|
217
|
+
metadata = relations[name]
|
218
|
+
if value.is_a?(Hash)
|
219
|
+
metadata.nested_builder(value, {}).build(self)
|
220
|
+
else
|
221
|
+
send("#{name}=", value)
|
188
222
|
end
|
189
223
|
end
|
190
224
|
end
|
191
225
|
|
192
|
-
#
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
226
|
+
# Return true if dynamic field setting is enabled.
|
227
|
+
#
|
228
|
+
# @example Is a set allowed for this name?
|
229
|
+
# person.set_allowed?(:title)
|
230
|
+
#
|
231
|
+
# @param [ String, Symbol ] key The name of the field.
|
232
|
+
#
|
233
|
+
# @return [ true, false ] True if allowed, false if not.
|
234
|
+
def set_allowed?(key)
|
235
|
+
Mongoid.allow_dynamic_fields && !respond_to?("#{key}=")
|
197
236
|
end
|
198
237
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
# accepts_nested_attributes_for :name, :addresses
|
211
|
-
# end
|
212
|
-
def accepts_nested_attributes_for(*args)
|
213
|
-
associations = args.flatten
|
214
|
-
options = associations.last.is_a?(Hash) ? associations.pop : {}
|
215
|
-
associations.each do |name|
|
216
|
-
define_method("#{name}_attributes=") do |attrs|
|
217
|
-
reject(attrs, options)
|
218
|
-
limit(attrs, name, options)
|
219
|
-
association = send(name)
|
220
|
-
if association
|
221
|
-
# observe(association, true)
|
222
|
-
association.nested_build(attrs, options)
|
223
|
-
else
|
224
|
-
send("build_#{name}", attrs, options)
|
225
|
-
end
|
226
|
-
end
|
227
|
-
end
|
228
|
-
end
|
238
|
+
# Return the typecasted value for a field.
|
239
|
+
#
|
240
|
+
# @example Get the value typecasted.
|
241
|
+
# person.typed_value_for(:title, :sir)
|
242
|
+
#
|
243
|
+
# @param [ String, Symbol ] key The field name.
|
244
|
+
# @param [ Object ] value The uncast value.
|
245
|
+
#
|
246
|
+
# @return [ Object ] The cast value.
|
247
|
+
def typed_value_for(key, value)
|
248
|
+
fields.has_key?(key) ? fields[key].set(value) : value
|
229
249
|
end
|
230
250
|
end
|
231
251
|
end
|