stonegao-mongoid 2.0.0.rc.6
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/LICENSE +20 -0
- data/README.rdoc +50 -0
- data/Rakefile +51 -0
- data/lib/config/locales/bg.yml +44 -0
- data/lib/config/locales/de.yml +44 -0
- data/lib/config/locales/en.yml +45 -0
- data/lib/config/locales/es.yml +44 -0
- data/lib/config/locales/fr.yml +45 -0
- data/lib/config/locales/hu.yml +47 -0
- data/lib/config/locales/it.yml +42 -0
- data/lib/config/locales/kr.yml +68 -0
- data/lib/config/locales/nl.yml +42 -0
- data/lib/config/locales/pl.yml +42 -0
- data/lib/config/locales/pt-br.yml +43 -0
- data/lib/config/locales/pt.yml +43 -0
- data/lib/config/locales/ro.yml +49 -0
- data/lib/config/locales/sv.yml +43 -0
- data/lib/config/locales/zh-CN.yml +34 -0
- data/lib/mongoid/atomicity.rb +111 -0
- data/lib/mongoid/attributes.rb +251 -0
- data/lib/mongoid/callbacks.rb +13 -0
- data/lib/mongoid/collection.rb +137 -0
- data/lib/mongoid/collections/cyclic_iterator.rb +34 -0
- data/lib/mongoid/collections/master.rb +29 -0
- data/lib/mongoid/collections/operations.rb +42 -0
- data/lib/mongoid/collections/slaves.rb +45 -0
- data/lib/mongoid/collections.rb +70 -0
- data/lib/mongoid/components.rb +45 -0
- data/lib/mongoid/config/database.rb +167 -0
- data/lib/mongoid/config/replset_database.rb +48 -0
- data/lib/mongoid/config.rb +343 -0
- data/lib/mongoid/contexts/enumerable/sort.rb +43 -0
- data/lib/mongoid/contexts/enumerable.rb +226 -0
- data/lib/mongoid/contexts/ids.rb +25 -0
- data/lib/mongoid/contexts/mongo.rb +345 -0
- data/lib/mongoid/contexts/paging.rb +50 -0
- data/lib/mongoid/contexts.rb +21 -0
- data/lib/mongoid/copyable.rb +44 -0
- data/lib/mongoid/criteria.rb +325 -0
- data/lib/mongoid/criterion/complex.rb +34 -0
- data/lib/mongoid/criterion/creational.rb +34 -0
- data/lib/mongoid/criterion/exclusion.rb +67 -0
- data/lib/mongoid/criterion/inclusion.rb +134 -0
- data/lib/mongoid/criterion/inspection.rb +20 -0
- data/lib/mongoid/criterion/optional.rb +213 -0
- data/lib/mongoid/criterion/selector.rb +74 -0
- data/lib/mongoid/cursor.rb +81 -0
- data/lib/mongoid/default_scope.rb +28 -0
- data/lib/mongoid/dirty.rb +251 -0
- data/lib/mongoid/document.rb +256 -0
- data/lib/mongoid/errors/document_not_found.rb +29 -0
- data/lib/mongoid/errors/invalid_collection.rb +19 -0
- data/lib/mongoid/errors/invalid_database.rb +20 -0
- data/lib/mongoid/errors/invalid_field.rb +19 -0
- data/lib/mongoid/errors/invalid_options.rb +16 -0
- data/lib/mongoid/errors/invalid_type.rb +26 -0
- data/lib/mongoid/errors/mongoid_error.rb +27 -0
- data/lib/mongoid/errors/too_many_nested_attribute_records.rb +21 -0
- data/lib/mongoid/errors/unsaved_document.rb +23 -0
- data/lib/mongoid/errors/unsupported_version.rb +21 -0
- data/lib/mongoid/errors/validations.rb +24 -0
- data/lib/mongoid/errors.rb +12 -0
- data/lib/mongoid/extensions/array/conversions.rb +23 -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 +27 -0
- data/lib/mongoid/extensions/date/conversions.rb +25 -0
- data/lib/mongoid/extensions/datetime/conversions.rb +12 -0
- data/lib/mongoid/extensions/false_class/equality.rb +13 -0
- data/lib/mongoid/extensions/float/conversions.rb +20 -0
- data/lib/mongoid/extensions/hash/conversions.rb +19 -0
- data/lib/mongoid/extensions/hash/criteria_helpers.rb +22 -0
- data/lib/mongoid/extensions/hash/scoping.rb +12 -0
- data/lib/mongoid/extensions/integer/conversions.rb +20 -0
- data/lib/mongoid/extensions/nil/collectionization.rb +12 -0
- data/lib/mongoid/extensions/object/conversions.rb +25 -0
- data/lib/mongoid/extensions/object/reflections.rb +17 -0
- data/lib/mongoid/extensions/object/yoda.rb +27 -0
- data/lib/mongoid/extensions/object_id/conversions.rb +57 -0
- data/lib/mongoid/extensions/proc/scoping.rb +12 -0
- data/lib/mongoid/extensions/set/conversions.rb +20 -0
- data/lib/mongoid/extensions/string/conversions.rb +34 -0
- data/lib/mongoid/extensions/string/inflections.rb +97 -0
- data/lib/mongoid/extensions/symbol/conversions.rb +21 -0
- data/lib/mongoid/extensions/symbol/inflections.rb +40 -0
- data/lib/mongoid/extensions/time_conversions.rb +38 -0
- data/lib/mongoid/extensions/true_class/equality.rb +13 -0
- data/lib/mongoid/extensions.rb +116 -0
- data/lib/mongoid/extras.rb +61 -0
- data/lib/mongoid/factory.rb +20 -0
- data/lib/mongoid/field.rb +95 -0
- data/lib/mongoid/fields.rb +138 -0
- data/lib/mongoid/finders.rb +173 -0
- data/lib/mongoid/hierarchy.rb +85 -0
- data/lib/mongoid/identity.rb +89 -0
- data/lib/mongoid/indexes.rb +38 -0
- data/lib/mongoid/inspection.rb +58 -0
- data/lib/mongoid/javascript/functions.yml +37 -0
- data/lib/mongoid/javascript.rb +21 -0
- data/lib/mongoid/json.rb +16 -0
- data/lib/mongoid/keys.rb +77 -0
- data/lib/mongoid/logger.rb +18 -0
- data/lib/mongoid/matchers/all.rb +11 -0
- data/lib/mongoid/matchers/default.rb +27 -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/matchers.rb +55 -0
- data/lib/mongoid/modifiers/command.rb +18 -0
- data/lib/mongoid/modifiers/inc.rb +24 -0
- data/lib/mongoid/modifiers.rb +24 -0
- data/lib/mongoid/multi_database.rb +11 -0
- data/lib/mongoid/multi_parameter_attributes.rb +80 -0
- data/lib/mongoid/named_scope.rb +36 -0
- data/lib/mongoid/nested_attributes.rb +43 -0
- data/lib/mongoid/paranoia.rb +103 -0
- data/lib/mongoid/paths.rb +61 -0
- data/lib/mongoid/persistence/command.rb +59 -0
- data/lib/mongoid/persistence/insert.rb +53 -0
- data/lib/mongoid/persistence/insert_embedded.rb +42 -0
- data/lib/mongoid/persistence/remove.rb +44 -0
- data/lib/mongoid/persistence/remove_all.rb +40 -0
- data/lib/mongoid/persistence/remove_embedded.rb +48 -0
- data/lib/mongoid/persistence/update.rb +76 -0
- data/lib/mongoid/persistence.rb +237 -0
- data/lib/mongoid/railtie.rb +129 -0
- data/lib/mongoid/railties/database.rake +171 -0
- data/lib/mongoid/railties/document.rb +12 -0
- data/lib/mongoid/relations/accessors.rb +157 -0
- data/lib/mongoid/relations/auto_save.rb +34 -0
- data/lib/mongoid/relations/binding.rb +26 -0
- data/lib/mongoid/relations/bindings/embedded/in.rb +82 -0
- data/lib/mongoid/relations/bindings/embedded/many.rb +98 -0
- data/lib/mongoid/relations/bindings/embedded/one.rb +66 -0
- data/lib/mongoid/relations/bindings/referenced/in.rb +74 -0
- data/lib/mongoid/relations/bindings/referenced/many.rb +96 -0
- data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +99 -0
- data/lib/mongoid/relations/bindings/referenced/one.rb +66 -0
- data/lib/mongoid/relations/bindings.rb +9 -0
- data/lib/mongoid/relations/builder.rb +42 -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/builders.rb +79 -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/cascading.rb +55 -0
- data/lib/mongoid/relations/constraint.rb +45 -0
- data/lib/mongoid/relations/cyclic.rb +97 -0
- data/lib/mongoid/relations/embedded/in.rb +173 -0
- data/lib/mongoid/relations/embedded/many.rb +483 -0
- data/lib/mongoid/relations/embedded/one.rb +170 -0
- data/lib/mongoid/relations/macros.rb +306 -0
- data/lib/mongoid/relations/many.rb +171 -0
- data/lib/mongoid/relations/metadata.rb +533 -0
- data/lib/mongoid/relations/nested_builder.rb +68 -0
- data/lib/mongoid/relations/one.rb +47 -0
- data/lib/mongoid/relations/polymorphic.rb +54 -0
- data/lib/mongoid/relations/proxy.rb +128 -0
- data/lib/mongoid/relations/referenced/in.rb +216 -0
- data/lib/mongoid/relations/referenced/many.rb +443 -0
- data/lib/mongoid/relations/referenced/many_to_many.rb +344 -0
- data/lib/mongoid/relations/referenced/one.rb +206 -0
- data/lib/mongoid/relations/reflections.rb +45 -0
- data/lib/mongoid/relations.rb +105 -0
- data/lib/mongoid/safe.rb +23 -0
- data/lib/mongoid/safety.rb +207 -0
- data/lib/mongoid/scope.rb +31 -0
- data/lib/mongoid/serialization.rb +99 -0
- data/lib/mongoid/state.rb +66 -0
- data/lib/mongoid/timestamps.rb +38 -0
- data/lib/mongoid/validations/associated.rb +42 -0
- data/lib/mongoid/validations/uniqueness.rb +85 -0
- data/lib/mongoid/validations.rb +117 -0
- data/lib/mongoid/version.rb +4 -0
- data/lib/mongoid/versioning.rb +51 -0
- data/lib/mongoid.rb +139 -0
- data/lib/rails/generators/mongoid/config/config_generator.rb +25 -0
- data/lib/rails/generators/mongoid/config/templates/mongoid.yml +23 -0
- data/lib/rails/generators/mongoid/model/model_generator.rb +24 -0
- data/lib/rails/generators/mongoid/model/templates/model.rb +17 -0
- data/lib/rails/generators/mongoid_generator.rb +61 -0
- data/lib/rails/mongoid.rb +57 -0
- metadata +380 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
require "mongoid/persistence/command"
|
|
3
|
+
require "mongoid/persistence/insert"
|
|
4
|
+
require "mongoid/persistence/insert_embedded"
|
|
5
|
+
require "mongoid/persistence/remove"
|
|
6
|
+
require "mongoid/persistence/remove_all"
|
|
7
|
+
require "mongoid/persistence/remove_embedded"
|
|
8
|
+
require "mongoid/persistence/update"
|
|
9
|
+
|
|
10
|
+
module Mongoid #:nodoc:
|
|
11
|
+
|
|
12
|
+
# The persistence module is a mixin to provide database accessor methods for
|
|
13
|
+
# the document. These correspond to the appropriate accessors on a
|
|
14
|
+
# mongo collection and retain the same DSL.
|
|
15
|
+
#
|
|
16
|
+
# @example Sample persistence operations.
|
|
17
|
+
# document.insert
|
|
18
|
+
# document.update
|
|
19
|
+
# document.upsert
|
|
20
|
+
module Persistence
|
|
21
|
+
extend ActiveSupport::Concern
|
|
22
|
+
|
|
23
|
+
# Remove the document from the datbase with callbacks.
|
|
24
|
+
#
|
|
25
|
+
# @example Destroy a document.
|
|
26
|
+
# document.destroy
|
|
27
|
+
#
|
|
28
|
+
# @param [ Hash ] options Options to pass to destroy.
|
|
29
|
+
#
|
|
30
|
+
# @return [ true, false ] True if successful, false if not.
|
|
31
|
+
def destroy(options = {})
|
|
32
|
+
run_callbacks(:destroy) { remove(options) }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Insert a new document into the database. Will return the document
|
|
36
|
+
# itself whether or not the save was successful.
|
|
37
|
+
#
|
|
38
|
+
# @example Insert a document.
|
|
39
|
+
# document.insert
|
|
40
|
+
#
|
|
41
|
+
# @param [ Hash ] options Options to pass to insert.
|
|
42
|
+
#
|
|
43
|
+
# @return [ Document ] The persisted document.
|
|
44
|
+
def insert(options = {})
|
|
45
|
+
Insert.new(self, options).persist
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Remove the document from the datbase.
|
|
49
|
+
#
|
|
50
|
+
# @example Remove the document.
|
|
51
|
+
# document.remove
|
|
52
|
+
#
|
|
53
|
+
# @param [ Hash ] options Options to pass to remove.
|
|
54
|
+
#
|
|
55
|
+
# @return [ TrueClass ] True.
|
|
56
|
+
def remove(options = {})
|
|
57
|
+
if Remove.new(self, options).persist
|
|
58
|
+
self.destroyed = true
|
|
59
|
+
cascade!
|
|
60
|
+
end; true
|
|
61
|
+
end
|
|
62
|
+
alias :delete :remove
|
|
63
|
+
|
|
64
|
+
# Save the document - will perform an insert if the document is new, and
|
|
65
|
+
# update if not. If a validation error occurs an error will get raised.
|
|
66
|
+
#
|
|
67
|
+
# @example Save the document.
|
|
68
|
+
# document.save!
|
|
69
|
+
#
|
|
70
|
+
# @param [ Hash ] options Options to pass to the save.
|
|
71
|
+
#
|
|
72
|
+
# @return [ true, false ] True if validation passed.
|
|
73
|
+
def save!(options = {})
|
|
74
|
+
self.class.fail_validate!(self) unless upsert; true
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Update the document in the datbase.
|
|
78
|
+
#
|
|
79
|
+
# @example Update an existing document.
|
|
80
|
+
# document.update
|
|
81
|
+
#
|
|
82
|
+
# @param [ Hash ] options Options to pass to update.
|
|
83
|
+
#
|
|
84
|
+
# @return [ true, false ] True if succeeded, false if not.
|
|
85
|
+
def update(options = {})
|
|
86
|
+
Update.new(self, options).persist
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Update a single attribute and persist the entire document.
|
|
90
|
+
# This skips validation but fires the callbacks.
|
|
91
|
+
#
|
|
92
|
+
# @example Update the attribute.
|
|
93
|
+
# person.update_attribute(:title, "Sir")
|
|
94
|
+
#
|
|
95
|
+
# @param [ Symbol, String ] name The name of the attribute.
|
|
96
|
+
# @param [ Object ] value The new value of the attribute.a
|
|
97
|
+
#
|
|
98
|
+
# @return [ true, false ] True if save was successfull, false if not.
|
|
99
|
+
#
|
|
100
|
+
# @since 2.0.0.rc.6
|
|
101
|
+
def update_attribute(name, value)
|
|
102
|
+
write_attribute(name, value) and save(:validate => false)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Update the document attributes in the datbase.
|
|
106
|
+
#
|
|
107
|
+
# @example Update the document's attributes
|
|
108
|
+
# document.update_attributes(:title => "Sir")
|
|
109
|
+
#
|
|
110
|
+
# @param [ Hash ] attributes The attributes to update.
|
|
111
|
+
#
|
|
112
|
+
# @return [ true, false ] True if validation passed, false if not.
|
|
113
|
+
def update_attributes(attributes = {})
|
|
114
|
+
write_attributes(attributes); save
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Update the document attributes in the database and raise an error if
|
|
118
|
+
# validation failed.
|
|
119
|
+
#
|
|
120
|
+
# @example Update the document's attributes.
|
|
121
|
+
# document.update_attributes(:title => "Sir")
|
|
122
|
+
#
|
|
123
|
+
# @param [ Hash ] attributes The attributes to update.
|
|
124
|
+
#
|
|
125
|
+
# @raise [ Errors::Validations ] If validation failed.
|
|
126
|
+
#
|
|
127
|
+
# @return [ true, false ] True if validation passed.
|
|
128
|
+
def update_attributes!(attributes = {})
|
|
129
|
+
update_attributes(attributes).tap do |result|
|
|
130
|
+
self.class.fail_validate!(self) unless result
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Upsert the document - will perform an insert if the document is new, and
|
|
135
|
+
# update if not.
|
|
136
|
+
#
|
|
137
|
+
# @example Upsert the document.
|
|
138
|
+
# document.upsert
|
|
139
|
+
#
|
|
140
|
+
# @param [ Hash ] options Options to pass to the upsert.
|
|
141
|
+
#
|
|
142
|
+
# @return [ true, false ] True is success, false if not.
|
|
143
|
+
def upsert(options = {})
|
|
144
|
+
if new_record?
|
|
145
|
+
insert(options).persisted?
|
|
146
|
+
else
|
|
147
|
+
update(options)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
alias :save :upsert
|
|
151
|
+
|
|
152
|
+
module ClassMethods #:nodoc:
|
|
153
|
+
|
|
154
|
+
# Create a new document. This will instantiate a new document and
|
|
155
|
+
# insert it in a single call. Will always return the document
|
|
156
|
+
# whether save passed or not.
|
|
157
|
+
#
|
|
158
|
+
# @example Create a new document.
|
|
159
|
+
# Person.create(:title => "Mr")
|
|
160
|
+
#
|
|
161
|
+
# @param [ Hash ] attributes The attributes to create with.
|
|
162
|
+
#
|
|
163
|
+
# @return [ Document ] The newly created document.
|
|
164
|
+
def create(attributes = {}, &block)
|
|
165
|
+
new(attributes, &block).tap(&:save)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Create a new document. This will instantiate a new document and
|
|
169
|
+
# insert it in a single call. Will always return the document
|
|
170
|
+
# whether save passed or not, and if validation fails an error will be
|
|
171
|
+
# raise.
|
|
172
|
+
#
|
|
173
|
+
# @example Create a new document.
|
|
174
|
+
# Person.create!(:title => "Mr")
|
|
175
|
+
#
|
|
176
|
+
# @param [ Hash ] attributes The attributes to create with.
|
|
177
|
+
#
|
|
178
|
+
# @return [ Document ] The newly created document.
|
|
179
|
+
def create!(attributes = {}, &block)
|
|
180
|
+
document = new(attributes, &block)
|
|
181
|
+
fail_validate!(document) if document.insert.errors.any?
|
|
182
|
+
document
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Delete all documents given the supplied conditions. If no conditions
|
|
186
|
+
# are passed, the entire collection will be dropped for performance
|
|
187
|
+
# benefits. Does not fire any callbacks.
|
|
188
|
+
#
|
|
189
|
+
# @example Delete matching documents from the collection.
|
|
190
|
+
# Person.delete_all(:conditions => { :title => "Sir" })
|
|
191
|
+
#
|
|
192
|
+
# @example Delete all documents from the collection.
|
|
193
|
+
# Person.delete_all
|
|
194
|
+
#
|
|
195
|
+
# @param [ Hash ] conditions Optional conditions to delete by.
|
|
196
|
+
#
|
|
197
|
+
# @return [ Integer ] The number of documents deleted.
|
|
198
|
+
def delete_all(conditions = {})
|
|
199
|
+
RemoveAll.new(
|
|
200
|
+
self,
|
|
201
|
+
{ :validate => false },
|
|
202
|
+
conditions[:conditions] || {}
|
|
203
|
+
).persist
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# Delete all documents given the supplied conditions. If no conditions
|
|
207
|
+
# are passed, the entire collection will be dropped for performance
|
|
208
|
+
# benefits. Fires the destroy callbacks if conditions were passed.
|
|
209
|
+
#
|
|
210
|
+
# @example Destroy matching documents from the collection.
|
|
211
|
+
# Person.destroy_all(:conditions => { :title => "Sir" })
|
|
212
|
+
#
|
|
213
|
+
# @example Destroy all documents from the collection.
|
|
214
|
+
# Person.destroy_all
|
|
215
|
+
#
|
|
216
|
+
# @param [ Hash ] conditions Optional conditions to destroy by.
|
|
217
|
+
#
|
|
218
|
+
# @return [ Integer ] The number of documents destroyed.
|
|
219
|
+
def destroy_all(conditions = {})
|
|
220
|
+
documents = all(conditions)
|
|
221
|
+
documents.count.tap do
|
|
222
|
+
documents.each { |doc| doc.destroy }
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# Raise an error if validation failed.
|
|
227
|
+
#
|
|
228
|
+
# @example Raise the validation error.
|
|
229
|
+
# Person.fail_validate!(person)
|
|
230
|
+
#
|
|
231
|
+
# @param [ Document ] document The document to fail.
|
|
232
|
+
def fail_validate!(document)
|
|
233
|
+
raise Errors::Validations.new(document)
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
end
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
require "singleton"
|
|
3
|
+
require "mongoid"
|
|
4
|
+
require "mongoid/config"
|
|
5
|
+
require "mongoid/railties/document"
|
|
6
|
+
require "rails"
|
|
7
|
+
require "rails/mongoid"
|
|
8
|
+
|
|
9
|
+
module Rails #:nodoc:
|
|
10
|
+
module Mongoid #:nodoc:
|
|
11
|
+
class Railtie < Rails::Railtie #:nodoc:
|
|
12
|
+
|
|
13
|
+
# Determine which generator to use. app_generators was introduced after
|
|
14
|
+
# 3.0.0.
|
|
15
|
+
#
|
|
16
|
+
# @example Get the generators method.
|
|
17
|
+
# railtie.generators
|
|
18
|
+
#
|
|
19
|
+
# @return [ Symbol ] The method name to use.
|
|
20
|
+
#
|
|
21
|
+
# @since 2.0.0.rc.4
|
|
22
|
+
def self.generator
|
|
23
|
+
config.respond_to?(:app_generators) ? :app_generators : :generators
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
config.send(generator).orm :mongoid, :migration => false
|
|
27
|
+
|
|
28
|
+
rake_tasks do
|
|
29
|
+
load "mongoid/railties/database.rake"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Exposes Mongoid's configuration to the Rails application configuration.
|
|
33
|
+
#
|
|
34
|
+
# @example Set up configuration in the Rails app.
|
|
35
|
+
# module MyApplication
|
|
36
|
+
# class Application < Rails::Application
|
|
37
|
+
# config.mongoid.logger = Logger.new($stdout, :warn)
|
|
38
|
+
# config.mongoid.reconnect_time = 10
|
|
39
|
+
# end
|
|
40
|
+
# end
|
|
41
|
+
config.mongoid = ::Mongoid::Config
|
|
42
|
+
|
|
43
|
+
# Initialize Mongoid. This will look for a mongoid.yml in the config
|
|
44
|
+
# directory and configure mongoid appropriately.
|
|
45
|
+
#
|
|
46
|
+
# @example mongoid.yml
|
|
47
|
+
#
|
|
48
|
+
# defaults: &defaults
|
|
49
|
+
# host: localhost
|
|
50
|
+
# slaves:
|
|
51
|
+
# # - host: localhost
|
|
52
|
+
# # port: 27018
|
|
53
|
+
# # - host: localhost
|
|
54
|
+
# # port: 27019
|
|
55
|
+
# allow_dynamic_fields: false
|
|
56
|
+
# parameterize_keys: false
|
|
57
|
+
# persist_in_safe_mode: false
|
|
58
|
+
#
|
|
59
|
+
# development:
|
|
60
|
+
# <<: *defaults
|
|
61
|
+
# database: mongoid
|
|
62
|
+
initializer "setup database" do
|
|
63
|
+
config_file = Rails.root.join("config", "mongoid.yml")
|
|
64
|
+
if config_file.file?
|
|
65
|
+
settings = YAML.load(ERB.new(config_file.read).result)[Rails.env]
|
|
66
|
+
::Mongoid.from_hash(settings) if settings.present?
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# After initialization we will warn the user if we can't find a mongoid.yml and
|
|
71
|
+
# alert to create one.
|
|
72
|
+
initializer "warn when configuration is missing" do
|
|
73
|
+
config.after_initialize do
|
|
74
|
+
unless Rails.root.join("config", "mongoid.yml").file?
|
|
75
|
+
puts "\nMongoid config not found. Create a config file at: config/mongoid.yml"
|
|
76
|
+
puts "to generate one run: rails generate mongoid:config\n\n"
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Due to all models not getting loaded and messing up inheritance queries
|
|
82
|
+
# and indexing, we need to preload the models in order to address this.
|
|
83
|
+
#
|
|
84
|
+
# This will happen every request in development, once in ther other
|
|
85
|
+
# environments.
|
|
86
|
+
initializer "preload all application models" do |app|
|
|
87
|
+
config.to_prepare do
|
|
88
|
+
::Rails::Mongoid.load_models(app) unless $rails_rake_task
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Set the proper error types for Rails. DocumentNotFound errors should be
|
|
93
|
+
# 404s and not 500s, validation errors are 422s.
|
|
94
|
+
initializer "load http errors" do |app|
|
|
95
|
+
config.after_initialize do
|
|
96
|
+
ActionDispatch::ShowExceptions.rescue_responses.update({
|
|
97
|
+
"Mongoid::Errors::DocumentNotFound" => :not_found,
|
|
98
|
+
"Mongoid::Errors::Validations" => 422
|
|
99
|
+
})
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# When workers are forked in passenger and unicorn, we need to reconnect
|
|
104
|
+
# to the database to all the workers do not share the same connection.
|
|
105
|
+
initializer "reconnect to master if application is preloaded" do
|
|
106
|
+
config.after_initialize do
|
|
107
|
+
|
|
108
|
+
# Unicorn clears the START_CTX when a worker is forked, so if we have
|
|
109
|
+
# data in START_CTX then we know we're being preloaded. Unicorn does
|
|
110
|
+
# not provide application-level hooks for executing code after the
|
|
111
|
+
# process has forked, so we reconnect lazily.
|
|
112
|
+
if defined?(Unicorn) && !Unicorn::HttpServer::START_CTX.empty?
|
|
113
|
+
::Mongoid.reconnect!(false)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Passenger provides the :starting_worker_process event for executing
|
|
117
|
+
# code after it has forked, so we use that and reconnect immediately.
|
|
118
|
+
if defined?(PhusionPassenger)
|
|
119
|
+
PhusionPassenger.on_event(:starting_worker_process) do |forked|
|
|
120
|
+
if forked
|
|
121
|
+
::Mongoid.reconnect!
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
namespace :db do
|
|
2
|
+
|
|
3
|
+
if not Rake::Task.task_defined?("db:drop")
|
|
4
|
+
desc 'Drops all the collections for the database for the current Rails.env'
|
|
5
|
+
task :drop => :environment do
|
|
6
|
+
Mongoid.master.collections.select {|c| c.name !~ /system/ }.each(&:drop)
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
if not Rake::Task.task_defined?("db:seed")
|
|
11
|
+
# if another ORM has defined db:seed, don't run it twice.
|
|
12
|
+
desc 'Load the seed data from db/seeds.rb'
|
|
13
|
+
task :seed => :environment do
|
|
14
|
+
seed_file = File.join(Rails.root, 'db', 'seeds.rb')
|
|
15
|
+
load(seed_file) if File.exist?(seed_file)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
if not Rake::Task.task_defined?("db:setup")
|
|
20
|
+
desc 'Create the database, and initialize with the seed data'
|
|
21
|
+
task :setup => [ 'db:create', 'db:mongoid:create_indexes', 'db:seed' ]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
if not Rake::Task.task_defined?("db:reseed")
|
|
25
|
+
desc 'Delete data and seed'
|
|
26
|
+
task :reseed => [ 'db:drop', 'db:seed' ]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
if not Rake::Task.task_defined?("db:create")
|
|
30
|
+
task :create => :environment do
|
|
31
|
+
# noop
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
if not Rake::Task.task_defined?("db:migrate")
|
|
36
|
+
task :migrate => :environment do
|
|
37
|
+
# noop
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
if not Rake::Task.task_defined?("db:schema:load")
|
|
42
|
+
namespace :schema do
|
|
43
|
+
task :load do
|
|
44
|
+
# noop
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
if not Rake::Task.task_defined?("db:test:prepare")
|
|
50
|
+
namespace :test do
|
|
51
|
+
task :prepare do
|
|
52
|
+
# noop
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
if not Rake::Task.task_defined?("db:create_indexes")
|
|
58
|
+
task :create_indexes => "mongoid:create_indexes"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
namespace :mongoid do
|
|
62
|
+
# gets a list of the mongoid models defined in the app/models directory
|
|
63
|
+
def get_mongoid_models
|
|
64
|
+
documents = []
|
|
65
|
+
Dir.glob("app/models/**/*.rb").sort.each do |file|
|
|
66
|
+
model_path = file[0..-4].split('/')[2..-1]
|
|
67
|
+
begin
|
|
68
|
+
klass = model_path.map(&:classify).join('::').constantize
|
|
69
|
+
if klass.ancestors.include?(Mongoid::Document) && !klass.embedded
|
|
70
|
+
documents << klass
|
|
71
|
+
end
|
|
72
|
+
rescue => e
|
|
73
|
+
# Just for non-mongoid objects that dont have the embedded
|
|
74
|
+
# attribute at the class level.
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
documents
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
desc 'Create the indexes defined on your mongoid models'
|
|
81
|
+
task :create_indexes => :environment do
|
|
82
|
+
::Rails::Mongoid.index_children(get_mongoid_models)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def convert_ids(obj)
|
|
86
|
+
if obj.is_a?(String) && obj =~ /^[a-f0-9]{24}$/
|
|
87
|
+
BSON::ObjectId(obj)
|
|
88
|
+
elsif obj.is_a?(Array)
|
|
89
|
+
obj.map do |v|
|
|
90
|
+
convert_ids(v)
|
|
91
|
+
end
|
|
92
|
+
elsif obj.is_a?(Hash)
|
|
93
|
+
obj.each do |k, v|
|
|
94
|
+
obj[k] = convert_ids(v)
|
|
95
|
+
end
|
|
96
|
+
else
|
|
97
|
+
obj
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def collection_names
|
|
102
|
+
@collection_names ||= get_mongoid_models.map{ |d| d.collection.name }.uniq
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
desc "Convert string objectids in mongo database to ObjectID type"
|
|
106
|
+
task :objectid_convert => :environment do
|
|
107
|
+
collection_names.each do |collection_name|
|
|
108
|
+
puts "Converting #{collection_name} to use ObjectIDs"
|
|
109
|
+
|
|
110
|
+
# get old collection
|
|
111
|
+
collection = Mongoid.master.collection(collection_name)
|
|
112
|
+
|
|
113
|
+
# get new collection (a clean one)
|
|
114
|
+
collection.db["#{collection_name}_new"].drop
|
|
115
|
+
new_collection = collection.db["#{collection_name}_new"]
|
|
116
|
+
|
|
117
|
+
# convert collection documents
|
|
118
|
+
collection.find({}, :timeout => false, :sort => "_id") do |cursor|
|
|
119
|
+
cursor.each do |doc|
|
|
120
|
+
new_doc = convert_ids(doc)
|
|
121
|
+
new_collection.insert(new_doc, :safe => true)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
puts "Done! Converted collection is in #{new_collection.name}\n\n"
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# no errors. great! now rename _new to collection_name
|
|
129
|
+
collection_names.each do |collection_name|
|
|
130
|
+
collection = Mongoid.master.collection(collection_name)
|
|
131
|
+
new_collection = collection.db["#{collection_name}_new"]
|
|
132
|
+
|
|
133
|
+
# swap collection to _old
|
|
134
|
+
puts "Moving #{collection.name} to #{collection_name}_old"
|
|
135
|
+
collection.db["#{collection_name}_old"].drop
|
|
136
|
+
|
|
137
|
+
begin
|
|
138
|
+
collection.rename("#{collection_name}_old")
|
|
139
|
+
rescue Exception => e
|
|
140
|
+
puts "Unable to rename database #{collection_name} to #{collection_name}_old"
|
|
141
|
+
puts "reason: #{e.message}\n\n"
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# swap _new to collection
|
|
145
|
+
puts "Moving #{new_collection.name} to #{collection_name}\n\n"
|
|
146
|
+
|
|
147
|
+
begin
|
|
148
|
+
new_collection.rename(collection_name)
|
|
149
|
+
rescue Exception => e
|
|
150
|
+
puts "Unable to rename database #{new_collection.name} to #{collection_name}"
|
|
151
|
+
puts "reason: #{e.message}\n\n"
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
puts "DONE! Run `rake db:mongoid:cleanup_old_collections` to remove old collections"
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
desc "Clean up old collections backed up by objectid_convert"
|
|
159
|
+
task :cleanup_old_collections => :environment do
|
|
160
|
+
collection_names.each do |collection_name|
|
|
161
|
+
collection = Mongoid.master.collection(collection_name)
|
|
162
|
+
collection.db["#{collection.name}_old"].drop
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
########
|
|
167
|
+
# TODO: lots more useful db tasks can be added here. stuff like copyDatabase, etc
|
|
168
|
+
########
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module Mongoid
|
|
2
|
+
module Document
|
|
3
|
+
# Used in conjunction with fields_for to build a form element for the
|
|
4
|
+
# destruction of this association. Always returns false because Mongoid
|
|
5
|
+
# only supports immediate deletion of associations.
|
|
6
|
+
#
|
|
7
|
+
# See ActionView::Helpers::FormHelper::fields_for for more info.
|
|
8
|
+
def _destroy
|
|
9
|
+
false
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Mongoid # :nodoc:
|
|
3
|
+
module Relations #:nodoc:
|
|
4
|
+
|
|
5
|
+
# This module contains all the behaviour related to accessing relations
|
|
6
|
+
# through the getters and setters, and how to delegate to builders to
|
|
7
|
+
# create new ones.
|
|
8
|
+
module Accessors
|
|
9
|
+
extend ActiveSupport::Concern
|
|
10
|
+
|
|
11
|
+
# Builds the related document and creates the relation unless the
|
|
12
|
+
# document is nil, then sets the relation on this document.
|
|
13
|
+
#
|
|
14
|
+
# @example Build the relation.
|
|
15
|
+
# person.build(:addresses, { :id => 1 }, metadata)
|
|
16
|
+
#
|
|
17
|
+
# @param [ String, Symbol ] name The name of the relation.
|
|
18
|
+
# @param [ Hash, BSON::ObjectId ] object The id or attributes to use.
|
|
19
|
+
# @param [ Metadata ] metadata The relation's metadata.
|
|
20
|
+
# @param [ true, false ] building If we are in a build operation.
|
|
21
|
+
#
|
|
22
|
+
# @return [ Proxy ] The relation.
|
|
23
|
+
#
|
|
24
|
+
# @since 2.0.0.rc.1
|
|
25
|
+
def build(name, object, metadata, options = {})
|
|
26
|
+
relation = create_relation(object, metadata)
|
|
27
|
+
set(name, relation).tap do |relation|
|
|
28
|
+
relation.load!(options) if relation && options[:eager]
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Return the options passed to the builders.
|
|
33
|
+
#
|
|
34
|
+
# @example Get the options.
|
|
35
|
+
# person.configurables(document, :continue => true)
|
|
36
|
+
#
|
|
37
|
+
# @param [ Array ] args The arguments to check.
|
|
38
|
+
#
|
|
39
|
+
# @return [ Hash ] The options.
|
|
40
|
+
#
|
|
41
|
+
# @since 2.0.0.rc.1
|
|
42
|
+
def options(args)
|
|
43
|
+
Mongoid.binding_defaults.merge(args.extract_options!)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Create a relation from an object and metadata.
|
|
47
|
+
#
|
|
48
|
+
# @example Create the relation.
|
|
49
|
+
# person.create_relation(document, metadata)
|
|
50
|
+
#
|
|
51
|
+
# @param [ Document, Array<Document ] object The relation target.
|
|
52
|
+
# @param [ Metadata ] metadata The relation metadata.
|
|
53
|
+
#
|
|
54
|
+
# @return [ Proxy ] The relation.
|
|
55
|
+
#
|
|
56
|
+
# @since 2.0.0.rc.1
|
|
57
|
+
def create_relation(object, metadata)
|
|
58
|
+
type = @attributes[metadata.inverse_type]
|
|
59
|
+
target = metadata.builder(object).build(type)
|
|
60
|
+
target ? metadata.relation.new(self, target, metadata) : nil
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Determines if the relation exists or not.
|
|
64
|
+
#
|
|
65
|
+
# @example Does the relation exist?
|
|
66
|
+
# person.relation_exists?(:people)
|
|
67
|
+
#
|
|
68
|
+
# @param [ String ] name The name of the relation to check.
|
|
69
|
+
#
|
|
70
|
+
# @return [ true, false ] True if set and not nil, false if not.
|
|
71
|
+
#
|
|
72
|
+
# @since 2.0.0.rc.1
|
|
73
|
+
def relation_exists?(name)
|
|
74
|
+
ivar(name)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Set the supplied relation to an instance variable on the class with the
|
|
78
|
+
# provided name. Used as a helper just for code cleanliness.
|
|
79
|
+
#
|
|
80
|
+
# @example Set the proxy on the document.
|
|
81
|
+
# person.set(:addresses, addresses)
|
|
82
|
+
#
|
|
83
|
+
# @param [ String, Symbol ] name The name of the relation.
|
|
84
|
+
# @param [ Proxy ] relation The relation to set.
|
|
85
|
+
#
|
|
86
|
+
# @return [ Proxy ] The relation.
|
|
87
|
+
#
|
|
88
|
+
# @since 2.0.0.rc.1
|
|
89
|
+
def set(name, relation)
|
|
90
|
+
instance_variable_set("@#{name}", relation)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
module ClassMethods #:nodoc:
|
|
94
|
+
|
|
95
|
+
# Defines the getter for the relation. Nothing too special here: just
|
|
96
|
+
# return the instance variable for the relation if it exists or build
|
|
97
|
+
# the thing.
|
|
98
|
+
#
|
|
99
|
+
# @example Set up the getter for the relation.
|
|
100
|
+
# Person.getter("addresses", metadata)
|
|
101
|
+
#
|
|
102
|
+
# @param [ String, Symbol ] name The name of the relation.
|
|
103
|
+
# @param [ Metadata ] metadata The metadata for the relation.
|
|
104
|
+
#
|
|
105
|
+
# @return [ Class ] The class being set up.
|
|
106
|
+
#
|
|
107
|
+
# @since 2.0.0.rc.1
|
|
108
|
+
def getter(name, metadata)
|
|
109
|
+
tap do
|
|
110
|
+
define_method(name) do |*args|
|
|
111
|
+
reload, variable = args.first, "@#{name}"
|
|
112
|
+
options = options(args)
|
|
113
|
+
if instance_variable_defined?(variable) && !reload
|
|
114
|
+
instance_variable_get(variable)
|
|
115
|
+
else
|
|
116
|
+
build(
|
|
117
|
+
name,
|
|
118
|
+
@attributes[metadata.key],
|
|
119
|
+
metadata,
|
|
120
|
+
options.merge(:binding => true, :eager => metadata.embedded?)
|
|
121
|
+
)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Defines the setter for the relation. This does a few things based on
|
|
128
|
+
# some conditions. If there is an existing association, a target
|
|
129
|
+
# substitution will take place, otherwise a new relation will be
|
|
130
|
+
# created with the supplied target.
|
|
131
|
+
#
|
|
132
|
+
# @example Set up the setter for the relation.
|
|
133
|
+
# Person.setter("addresses", metadata)
|
|
134
|
+
#
|
|
135
|
+
# @param [ String, Symbol ] name The name of the relation.
|
|
136
|
+
# @param [ Metadata ] metadata The metadata for the relation.
|
|
137
|
+
#
|
|
138
|
+
# @return [ Class ] The class being set up.
|
|
139
|
+
#
|
|
140
|
+
# @since 2.0.0.rc.1
|
|
141
|
+
def setter(name, metadata)
|
|
142
|
+
tap do
|
|
143
|
+
define_method("#{name}=") do |*args|
|
|
144
|
+
object, options = args.first, options(args)
|
|
145
|
+
variable = "@#{name}"
|
|
146
|
+
if relation_exists?(name) && !object.is_a?(Hash)
|
|
147
|
+
set(name, ivar(name).substitute(object, options))
|
|
148
|
+
else
|
|
149
|
+
build(name, object, metadata, options.merge(:eager => true))
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|