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.
Files changed (199) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +50 -0
  3. data/Rakefile +51 -0
  4. data/lib/config/locales/bg.yml +44 -0
  5. data/lib/config/locales/de.yml +44 -0
  6. data/lib/config/locales/en.yml +45 -0
  7. data/lib/config/locales/es.yml +44 -0
  8. data/lib/config/locales/fr.yml +45 -0
  9. data/lib/config/locales/hu.yml +47 -0
  10. data/lib/config/locales/it.yml +42 -0
  11. data/lib/config/locales/kr.yml +68 -0
  12. data/lib/config/locales/nl.yml +42 -0
  13. data/lib/config/locales/pl.yml +42 -0
  14. data/lib/config/locales/pt-br.yml +43 -0
  15. data/lib/config/locales/pt.yml +43 -0
  16. data/lib/config/locales/ro.yml +49 -0
  17. data/lib/config/locales/sv.yml +43 -0
  18. data/lib/config/locales/zh-CN.yml +34 -0
  19. data/lib/mongoid/atomicity.rb +111 -0
  20. data/lib/mongoid/attributes.rb +251 -0
  21. data/lib/mongoid/callbacks.rb +13 -0
  22. data/lib/mongoid/collection.rb +137 -0
  23. data/lib/mongoid/collections/cyclic_iterator.rb +34 -0
  24. data/lib/mongoid/collections/master.rb +29 -0
  25. data/lib/mongoid/collections/operations.rb +42 -0
  26. data/lib/mongoid/collections/slaves.rb +45 -0
  27. data/lib/mongoid/collections.rb +70 -0
  28. data/lib/mongoid/components.rb +45 -0
  29. data/lib/mongoid/config/database.rb +167 -0
  30. data/lib/mongoid/config/replset_database.rb +48 -0
  31. data/lib/mongoid/config.rb +343 -0
  32. data/lib/mongoid/contexts/enumerable/sort.rb +43 -0
  33. data/lib/mongoid/contexts/enumerable.rb +226 -0
  34. data/lib/mongoid/contexts/ids.rb +25 -0
  35. data/lib/mongoid/contexts/mongo.rb +345 -0
  36. data/lib/mongoid/contexts/paging.rb +50 -0
  37. data/lib/mongoid/contexts.rb +21 -0
  38. data/lib/mongoid/copyable.rb +44 -0
  39. data/lib/mongoid/criteria.rb +325 -0
  40. data/lib/mongoid/criterion/complex.rb +34 -0
  41. data/lib/mongoid/criterion/creational.rb +34 -0
  42. data/lib/mongoid/criterion/exclusion.rb +67 -0
  43. data/lib/mongoid/criterion/inclusion.rb +134 -0
  44. data/lib/mongoid/criterion/inspection.rb +20 -0
  45. data/lib/mongoid/criterion/optional.rb +213 -0
  46. data/lib/mongoid/criterion/selector.rb +74 -0
  47. data/lib/mongoid/cursor.rb +81 -0
  48. data/lib/mongoid/default_scope.rb +28 -0
  49. data/lib/mongoid/dirty.rb +251 -0
  50. data/lib/mongoid/document.rb +256 -0
  51. data/lib/mongoid/errors/document_not_found.rb +29 -0
  52. data/lib/mongoid/errors/invalid_collection.rb +19 -0
  53. data/lib/mongoid/errors/invalid_database.rb +20 -0
  54. data/lib/mongoid/errors/invalid_field.rb +19 -0
  55. data/lib/mongoid/errors/invalid_options.rb +16 -0
  56. data/lib/mongoid/errors/invalid_type.rb +26 -0
  57. data/lib/mongoid/errors/mongoid_error.rb +27 -0
  58. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +21 -0
  59. data/lib/mongoid/errors/unsaved_document.rb +23 -0
  60. data/lib/mongoid/errors/unsupported_version.rb +21 -0
  61. data/lib/mongoid/errors/validations.rb +24 -0
  62. data/lib/mongoid/errors.rb +12 -0
  63. data/lib/mongoid/extensions/array/conversions.rb +23 -0
  64. data/lib/mongoid/extensions/array/parentization.rb +13 -0
  65. data/lib/mongoid/extensions/big_decimal/conversions.rb +19 -0
  66. data/lib/mongoid/extensions/binary/conversions.rb +17 -0
  67. data/lib/mongoid/extensions/boolean/conversions.rb +27 -0
  68. data/lib/mongoid/extensions/date/conversions.rb +25 -0
  69. data/lib/mongoid/extensions/datetime/conversions.rb +12 -0
  70. data/lib/mongoid/extensions/false_class/equality.rb +13 -0
  71. data/lib/mongoid/extensions/float/conversions.rb +20 -0
  72. data/lib/mongoid/extensions/hash/conversions.rb +19 -0
  73. data/lib/mongoid/extensions/hash/criteria_helpers.rb +22 -0
  74. data/lib/mongoid/extensions/hash/scoping.rb +12 -0
  75. data/lib/mongoid/extensions/integer/conversions.rb +20 -0
  76. data/lib/mongoid/extensions/nil/collectionization.rb +12 -0
  77. data/lib/mongoid/extensions/object/conversions.rb +25 -0
  78. data/lib/mongoid/extensions/object/reflections.rb +17 -0
  79. data/lib/mongoid/extensions/object/yoda.rb +27 -0
  80. data/lib/mongoid/extensions/object_id/conversions.rb +57 -0
  81. data/lib/mongoid/extensions/proc/scoping.rb +12 -0
  82. data/lib/mongoid/extensions/set/conversions.rb +20 -0
  83. data/lib/mongoid/extensions/string/conversions.rb +34 -0
  84. data/lib/mongoid/extensions/string/inflections.rb +97 -0
  85. data/lib/mongoid/extensions/symbol/conversions.rb +21 -0
  86. data/lib/mongoid/extensions/symbol/inflections.rb +40 -0
  87. data/lib/mongoid/extensions/time_conversions.rb +38 -0
  88. data/lib/mongoid/extensions/true_class/equality.rb +13 -0
  89. data/lib/mongoid/extensions.rb +116 -0
  90. data/lib/mongoid/extras.rb +61 -0
  91. data/lib/mongoid/factory.rb +20 -0
  92. data/lib/mongoid/field.rb +95 -0
  93. data/lib/mongoid/fields.rb +138 -0
  94. data/lib/mongoid/finders.rb +173 -0
  95. data/lib/mongoid/hierarchy.rb +85 -0
  96. data/lib/mongoid/identity.rb +89 -0
  97. data/lib/mongoid/indexes.rb +38 -0
  98. data/lib/mongoid/inspection.rb +58 -0
  99. data/lib/mongoid/javascript/functions.yml +37 -0
  100. data/lib/mongoid/javascript.rb +21 -0
  101. data/lib/mongoid/json.rb +16 -0
  102. data/lib/mongoid/keys.rb +77 -0
  103. data/lib/mongoid/logger.rb +18 -0
  104. data/lib/mongoid/matchers/all.rb +11 -0
  105. data/lib/mongoid/matchers/default.rb +27 -0
  106. data/lib/mongoid/matchers/exists.rb +13 -0
  107. data/lib/mongoid/matchers/gt.rb +11 -0
  108. data/lib/mongoid/matchers/gte.rb +11 -0
  109. data/lib/mongoid/matchers/in.rb +11 -0
  110. data/lib/mongoid/matchers/lt.rb +11 -0
  111. data/lib/mongoid/matchers/lte.rb +11 -0
  112. data/lib/mongoid/matchers/ne.rb +11 -0
  113. data/lib/mongoid/matchers/nin.rb +11 -0
  114. data/lib/mongoid/matchers/size.rb +11 -0
  115. data/lib/mongoid/matchers.rb +55 -0
  116. data/lib/mongoid/modifiers/command.rb +18 -0
  117. data/lib/mongoid/modifiers/inc.rb +24 -0
  118. data/lib/mongoid/modifiers.rb +24 -0
  119. data/lib/mongoid/multi_database.rb +11 -0
  120. data/lib/mongoid/multi_parameter_attributes.rb +80 -0
  121. data/lib/mongoid/named_scope.rb +36 -0
  122. data/lib/mongoid/nested_attributes.rb +43 -0
  123. data/lib/mongoid/paranoia.rb +103 -0
  124. data/lib/mongoid/paths.rb +61 -0
  125. data/lib/mongoid/persistence/command.rb +59 -0
  126. data/lib/mongoid/persistence/insert.rb +53 -0
  127. data/lib/mongoid/persistence/insert_embedded.rb +42 -0
  128. data/lib/mongoid/persistence/remove.rb +44 -0
  129. data/lib/mongoid/persistence/remove_all.rb +40 -0
  130. data/lib/mongoid/persistence/remove_embedded.rb +48 -0
  131. data/lib/mongoid/persistence/update.rb +76 -0
  132. data/lib/mongoid/persistence.rb +237 -0
  133. data/lib/mongoid/railtie.rb +129 -0
  134. data/lib/mongoid/railties/database.rake +171 -0
  135. data/lib/mongoid/railties/document.rb +12 -0
  136. data/lib/mongoid/relations/accessors.rb +157 -0
  137. data/lib/mongoid/relations/auto_save.rb +34 -0
  138. data/lib/mongoid/relations/binding.rb +26 -0
  139. data/lib/mongoid/relations/bindings/embedded/in.rb +82 -0
  140. data/lib/mongoid/relations/bindings/embedded/many.rb +98 -0
  141. data/lib/mongoid/relations/bindings/embedded/one.rb +66 -0
  142. data/lib/mongoid/relations/bindings/referenced/in.rb +74 -0
  143. data/lib/mongoid/relations/bindings/referenced/many.rb +96 -0
  144. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +99 -0
  145. data/lib/mongoid/relations/bindings/referenced/one.rb +66 -0
  146. data/lib/mongoid/relations/bindings.rb +9 -0
  147. data/lib/mongoid/relations/builder.rb +42 -0
  148. data/lib/mongoid/relations/builders/embedded/in.rb +25 -0
  149. data/lib/mongoid/relations/builders/embedded/many.rb +32 -0
  150. data/lib/mongoid/relations/builders/embedded/one.rb +26 -0
  151. data/lib/mongoid/relations/builders/nested_attributes/many.rb +116 -0
  152. data/lib/mongoid/relations/builders/nested_attributes/one.rb +135 -0
  153. data/lib/mongoid/relations/builders/referenced/in.rb +32 -0
  154. data/lib/mongoid/relations/builders/referenced/many.rb +26 -0
  155. data/lib/mongoid/relations/builders/referenced/many_to_many.rb +29 -0
  156. data/lib/mongoid/relations/builders/referenced/one.rb +30 -0
  157. data/lib/mongoid/relations/builders.rb +79 -0
  158. data/lib/mongoid/relations/cascading/delete.rb +19 -0
  159. data/lib/mongoid/relations/cascading/destroy.rb +19 -0
  160. data/lib/mongoid/relations/cascading/nullify.rb +18 -0
  161. data/lib/mongoid/relations/cascading/strategy.rb +26 -0
  162. data/lib/mongoid/relations/cascading.rb +55 -0
  163. data/lib/mongoid/relations/constraint.rb +45 -0
  164. data/lib/mongoid/relations/cyclic.rb +97 -0
  165. data/lib/mongoid/relations/embedded/in.rb +173 -0
  166. data/lib/mongoid/relations/embedded/many.rb +483 -0
  167. data/lib/mongoid/relations/embedded/one.rb +170 -0
  168. data/lib/mongoid/relations/macros.rb +306 -0
  169. data/lib/mongoid/relations/many.rb +171 -0
  170. data/lib/mongoid/relations/metadata.rb +533 -0
  171. data/lib/mongoid/relations/nested_builder.rb +68 -0
  172. data/lib/mongoid/relations/one.rb +47 -0
  173. data/lib/mongoid/relations/polymorphic.rb +54 -0
  174. data/lib/mongoid/relations/proxy.rb +128 -0
  175. data/lib/mongoid/relations/referenced/in.rb +216 -0
  176. data/lib/mongoid/relations/referenced/many.rb +443 -0
  177. data/lib/mongoid/relations/referenced/many_to_many.rb +344 -0
  178. data/lib/mongoid/relations/referenced/one.rb +206 -0
  179. data/lib/mongoid/relations/reflections.rb +45 -0
  180. data/lib/mongoid/relations.rb +105 -0
  181. data/lib/mongoid/safe.rb +23 -0
  182. data/lib/mongoid/safety.rb +207 -0
  183. data/lib/mongoid/scope.rb +31 -0
  184. data/lib/mongoid/serialization.rb +99 -0
  185. data/lib/mongoid/state.rb +66 -0
  186. data/lib/mongoid/timestamps.rb +38 -0
  187. data/lib/mongoid/validations/associated.rb +42 -0
  188. data/lib/mongoid/validations/uniqueness.rb +85 -0
  189. data/lib/mongoid/validations.rb +117 -0
  190. data/lib/mongoid/version.rb +4 -0
  191. data/lib/mongoid/versioning.rb +51 -0
  192. data/lib/mongoid.rb +139 -0
  193. data/lib/rails/generators/mongoid/config/config_generator.rb +25 -0
  194. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +23 -0
  195. data/lib/rails/generators/mongoid/model/model_generator.rb +24 -0
  196. data/lib/rails/generators/mongoid/model/templates/model.rb +17 -0
  197. data/lib/rails/generators/mongoid_generator.rb +61 -0
  198. data/lib/rails/mongoid.rb +57 -0
  199. 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