mongoid 2.0.0.beta.14 → 2.0.0.beta.15

Sign up to get free protection for your applications and to get access to all the features.
@@ -64,6 +64,7 @@ require "mongoid/hierarchy"
64
64
  require "mongoid/identity"
65
65
  require "mongoid/indexes"
66
66
  require "mongoid/javascript"
67
+ require "mongoid/json"
67
68
  require "mongoid/keys"
68
69
  require "mongoid/logger"
69
70
  require "mongoid/matchers"
@@ -20,8 +20,9 @@ module Mongoid # :nodoc:
20
20
  cattr_accessor :embedded
21
21
  self.embedded = false
22
22
 
23
- class_inheritable_accessor :associations
23
+ class_inheritable_accessor :associations, :cascades
24
24
  self.associations = {}
25
+ self.cascades = {}
25
26
 
26
27
  delegate :embedded, :embedded?, :to => "self.class"
27
28
  end
@@ -57,8 +58,8 @@ module Mongoid # :nodoc:
57
58
  next unless association.macro == :referenced_in
58
59
  foreign_key = association.options.foreign_key
59
60
  if send(foreign_key).nil?
60
- target = send(name)
61
- send("#{foreign_key}=", target ? target.id : nil)
61
+ proxy = send(name)
62
+ send("#{foreign_key}=", proxy && proxy.target ? proxy.id : nil)
62
63
  end
63
64
  end
64
65
  end
@@ -204,6 +205,7 @@ module Mongoid # :nodoc:
204
205
  set_callback :save, :before do |document|
205
206
  document.update_associations(name)
206
207
  end
208
+ add_cascade(name, options)
207
209
  end
208
210
 
209
211
  alias :has_many_related :references_many
@@ -223,10 +225,14 @@ module Mongoid # :nodoc:
223
225
  # end
224
226
  def references_one(name, options = {}, &block)
225
227
  opts = optionize(name, options, constraint(name, options, :one), &block)
226
- associate(Associations::ReferencesOne, opts)
228
+ type = Associations::ReferencesOne
229
+ associate(type, opts)
230
+ add_builder(type, opts)
231
+ add_creator(type, opts)
227
232
  set_callback :save, :before do |document|
228
233
  document.update_association(name)
229
234
  end
235
+ add_cascade(name, options)
230
236
  end
231
237
 
232
238
  alias :has_one_related :references_one
@@ -269,7 +275,20 @@ module Mongoid # :nodoc:
269
275
  def associate(type, options)
270
276
  name = options.name.to_s
271
277
  associations[name] = MetaData.new(type, options)
272
- define_method(name) { memoized(name) { type.instantiate(self, options) } }
278
+ define_method(name) do
279
+ memoized(name) do
280
+ proxy = type.new(self, options)
281
+ case proxy
282
+ when Associations::ReferencesOne,
283
+ Associations::EmbedsOne,
284
+ Associations::ReferencedIn,
285
+ Associations::EmbeddedIn
286
+ proxy.target ? proxy : nil
287
+ else
288
+ proxy
289
+ end
290
+ end
291
+ end
273
292
  define_method("#{name}=") do |object|
274
293
  unmemoize(name)
275
294
  memoized(name) { type.update(object, self, options) }
@@ -284,10 +303,10 @@ module Mongoid # :nodoc:
284
303
  attrs = params[0]
285
304
  attr_options = params[1] || {}
286
305
  reset(name) do
287
- unless type == Associations::EmbedsOne && attr_options[:update_only]
288
- type.new(self, (attrs || {}).stringify_keys, options)
289
- end
290
- end
306
+ proxy = type.new(self, options)
307
+ proxy.build((attrs || {}).stringify_keys)
308
+ proxy
309
+ end unless type == Associations::EmbedsOne && attr_options[:update_only]
291
310
  end
292
311
  end
293
312
 
@@ -304,6 +323,12 @@ module Mongoid # :nodoc:
304
323
  end
305
324
  end
306
325
 
326
+ # Create the callbacks for dependent deletes and destroys.
327
+ def add_cascade(name, options)
328
+ dependent = options[:dependent]
329
+ self.cascades[name] = dependent if dependent
330
+ end
331
+
307
332
  # build the options given the params.
308
333
  def optionize(name, options, foreign_key, &block)
309
334
  Associations::Options.new(
@@ -14,10 +14,16 @@ module Mongoid #:nodoc:
14
14
  #
15
15
  # Options:
16
16
  #
17
- # target: The parent +Document+
17
+ # document: The child +Document+
18
18
  # options: The association options
19
- def initialize(target, options)
20
- @target, @options = target, options
19
+ def initialize(document, options, target = nil)
20
+ if target
21
+ inverse = determine_name(target, options)
22
+ document.parentize(target, inverse)
23
+ document.notify
24
+ target.unmemoize(inverse)
25
+ end
26
+ @target, @options = document._parent, options
21
27
  extends(options)
22
28
  end
23
29
 
@@ -28,20 +34,14 @@ module Mongoid #:nodoc:
28
34
  @target
29
35
  end
30
36
 
31
- class << self
32
- # Creates the new association by setting the internal
33
- # document as the passed in Document. This should be the
34
- # parent.
35
- #
36
- # Options:
37
- #
38
- # document: The parent +Document+
39
- # options: The association options
40
- def instantiate(document, options)
41
- target = document._parent
42
- target.nil? ? nil : new(target, options)
43
- end
37
+ protected
38
+ def determine_name(target, options)
39
+ inverse = options.inverse_of
40
+ return inverse unless inverse.is_a?(Array)
41
+ inverse.detect { |name| target.respond_to?(name) }
42
+ end
44
43
 
44
+ class << self
45
45
  # Returns the macro used to create the association.
46
46
  def macro
47
47
  :embedded_in
@@ -55,18 +55,7 @@ module Mongoid #:nodoc:
55
55
  #
56
56
  # A new +EmbeddedIn+ association proxy.
57
57
  def update(target, child, options)
58
- inverse = determine_name(target, options)
59
- child.parentize(target, inverse)
60
- child.notify
61
- target.unmemoize(inverse)
62
- instantiate(child, options)
63
- end
64
-
65
- protected
66
- def determine_name(target, options)
67
- inverse = options.inverse_of
68
- return inverse unless inverse.is_a?(Array)
69
- inverse.detect { |name| target.respond_to?(name) }
58
+ new(child, options, target)
70
59
  end
71
60
  end
72
61
  end
@@ -250,18 +250,6 @@ module Mongoid #:nodoc:
250
250
  end
251
251
 
252
252
  class << self
253
-
254
- # Preferred method of creating a new +EmbedsMany+ association. It will
255
- # delegate to new.
256
- #
257
- # Options:
258
- #
259
- # document: The parent +Document+
260
- # options: The association options
261
- def instantiate(document, options, target_array = nil)
262
- new(document, options, target_array)
263
- end
264
-
265
253
  # Returns the macro used to create the association.
266
254
  def macro
267
255
  :embeds_many
@@ -274,9 +262,9 @@ module Mongoid #:nodoc:
274
262
  parent.raw_attributes.delete(options.name)
275
263
  children.assimilate(parent, options)
276
264
  if children && children.first.is_a?(Mongoid::Document)
277
- instantiate(parent, options, children)
265
+ new(parent, options, children)
278
266
  else
279
- instantiate(parent, options)
267
+ new(parent, options)
280
268
  end
281
269
  end
282
270
  end
@@ -10,6 +10,14 @@ module Mongoid #:nodoc:
10
10
  @target = attrs.assimilate(@parent, @options, type); self
11
11
  end
12
12
 
13
+ # Replaces the target with a new object
14
+ #
15
+ # Returns the association proxy
16
+ def replace(obj)
17
+ @target = obj
18
+ self
19
+ end
20
+
13
21
  # Creates the new association by finding the attributes in
14
22
  # the parent document with its name, and instantiating a
15
23
  # new document for it.
@@ -26,9 +34,16 @@ module Mongoid #:nodoc:
26
34
  # Returns:
27
35
  #
28
36
  # A new +HashOne+ association proxy.
29
- def initialize(document, attrs, options, target = nil)
37
+ def initialize(document, options, target = nil)
30
38
  @parent, @options = document, options
31
- @target = target ? target : attrs.assimilate(@parent, @options, attrs.klass)
39
+
40
+ if target
41
+ replace(target)
42
+ else
43
+ attributes = document.raw_attributes[options.name]
44
+ build(attributes) unless attributes.blank?
45
+ end
46
+
32
47
  extends(options)
33
48
  end
34
49
 
@@ -49,23 +64,6 @@ module Mongoid #:nodoc:
49
64
  end
50
65
 
51
66
  class << self
52
- # Preferred method of instantiating a new +EmbedsOne+, since nil values
53
- # will be handled properly.
54
- #
55
- # Options:
56
- #
57
- # document: The parent +Document+
58
- # options: The association options.
59
- #
60
- # Returns:
61
- #
62
- # A new +EmbedsOne+ association proxy.
63
- def instantiate(document, options, target = nil)
64
- attributes = document.raw_attributes[options.name]
65
- return nil if attributes.blank? && target.nil?
66
- new(document, attributes, options, target)
67
- end
68
-
69
67
  # Returns the macro used to create the association.
70
68
  def macro
71
69
  :embeds_one
@@ -89,7 +87,7 @@ module Mongoid #:nodoc:
89
87
  # A new +EmbedsOne+ association proxy.
90
88
  def update(child, parent, options)
91
89
  child.assimilate(parent, options)
92
- instantiate(parent, options, child.is_a?(Hash) ? nil : child)
90
+ new(parent, options, child.is_a?(Hash) ? nil : child)
93
91
  end
94
92
  end
95
93
  end
@@ -9,6 +9,12 @@ module Mongoid #:nodoc:
9
9
  self.merge!(attributes)
10
10
  end
11
11
 
12
+ # For relational associations we want to know if we cascade deletes or
13
+ # destroys to associations.
14
+ def dependent
15
+ self[:dependent]
16
+ end
17
+
12
18
  # Returns the extension if it exists, nil if not.
13
19
  def extension
14
20
  self[:extend]
@@ -11,27 +11,28 @@ module Mongoid #:nodoc:
11
11
  #
12
12
  # document: The +Document+ that contains the relationship.
13
13
  # options: The association +Options+.
14
- def initialize(document, foreign_key, options, target = nil)
14
+ def initialize(document, options, target = nil)
15
15
  @options = options
16
- @target = target || options.klass.find(foreign_key)
17
- extends(options)
18
- end
19
16
 
20
- class << self
21
- # Instantiate a new +ReferencedIn+ or return nil if the foreign key is
22
- # nil. It is preferrable to use this method over the traditional call
23
- # to new.
24
- #
25
- # Options:
26
- #
27
- # document: The +Document+ that contains the relationship.
28
- # options: The association +Options+.
29
- def instantiate(document, options, target = nil)
17
+ if target
18
+ replace(target)
19
+ else
30
20
  foreign_key = document.send(options.foreign_key)
31
- return nil if foreign_key.blank? && target.nil?
32
- new(document, foreign_key, options, target)
21
+ replace(options.klass.find(foreign_key)) unless foreign_key.blank?
33
22
  end
34
23
 
24
+ extends(options)
25
+ end
26
+
27
+ # Replaces the target with a new object
28
+ #
29
+ # Returns the association proxy
30
+ def replace(obj)
31
+ @target = obj
32
+ self
33
+ end
34
+
35
+ class << self
35
36
  # Returns the macro used to create the association.
36
37
  def macro
37
38
  :referenced_in
@@ -51,7 +52,7 @@ module Mongoid #:nodoc:
51
52
  # <tt>ReferencedIn.update(person, game, options)</tt>
52
53
  def update(target, document, options)
53
54
  document.send("#{options.foreign_key}=", target ? target.id : nil)
54
- instantiate(document, options, target)
55
+ new(document, options, target)
55
56
  end
56
57
  end
57
58
  end
@@ -86,7 +86,7 @@ module Mongoid #:nodoc:
86
86
  #
87
87
  # Example:
88
88
  #
89
- # <tt>RelatesToManyAsArray.update(preferences, person, options)</tt>
89
+ # <tt>ReferencesManyAsArray.update(preferences, person, options)</tt>
90
90
  def update(target, document, options)
91
91
  target.each do |child|
92
92
  document.send(options.name) << child
@@ -5,19 +5,13 @@ module Mongoid #:nodoc:
5
5
  # separate collection or database.
6
6
  class ReferencesOne < Proxy
7
7
 
8
- delegate :nil?, :to => :target
9
-
10
8
  # Builds a new Document and sets it as the association.
11
9
  #
12
10
  # Returns the newly created object.
13
11
  def build(attributes = {})
14
- @target = @klass.instantiate(attributes)
15
- inverse = @target.associations.values.detect do |metadata|
16
- metadata.options.klass == @parent.class
17
- end
18
- name = inverse.name
19
- @target.send("#{name}=", @parent)
20
- @target
12
+ target = @klass.instantiate(attributes)
13
+ replace(target)
14
+ target
21
15
  end
22
16
 
23
17
  # Builds a new Document and sets it as the association, then saves the
@@ -28,6 +22,20 @@ module Mongoid #:nodoc:
28
22
  build(attributes).tap(&:save)
29
23
  end
30
24
 
25
+ # Replaces the target with a new object
26
+ #
27
+ # Returns the association proxy
28
+ def replace(obj)
29
+ @target = obj
30
+ inverse = @target.associations.values.detect do |metadata|
31
+ metadata.options.klass == @parent.class
32
+ end
33
+ name = inverse.name
34
+ @target.send("#{name}=", @parent)
35
+
36
+ self
37
+ end
38
+
31
39
  # Initializing a related association only requires looking up the objects
32
40
  # by their ids.
33
41
  #
@@ -35,10 +43,10 @@ module Mongoid #:nodoc:
35
43
  #
36
44
  # document: The +Document+ that contains the relationship.
37
45
  # options: The association +Options+.
38
- def initialize(document, options, target = nil)
46
+ def initialize(document, options)
39
47
  @parent, @klass = document, options.klass
40
48
  @foreign_key = options.foreign_key
41
- @target = target || @klass.first(:conditions => { @foreign_key => @parent.id })
49
+ @target = @klass.first(:conditions => { @foreign_key => @parent.id })
42
50
  extends(options)
43
51
  end
44
52
 
@@ -57,16 +65,6 @@ module Mongoid #:nodoc:
57
65
  end
58
66
 
59
67
  class << self
60
- # Preferred method for creating the new +RelatesToMany+ association.
61
- #
62
- # Options:
63
- #
64
- # document: The +Document+ that contains the relationship.
65
- # options: The association +Options+.
66
- def instantiate(document, options, target = nil)
67
- new(document, options, target)
68
- end
69
-
70
68
  # Returns the macro used to create the association.
71
69
  def macro
72
70
  :references_one
@@ -87,10 +85,10 @@ module Mongoid #:nodoc:
87
85
  def update(target, document, options)
88
86
  if target
89
87
  name = document.class.to_s.underscore
90
- target.send("#{name}=", document)
91
- return instantiate(document, options, target)
88
+ proxy = new(document, options)
89
+ proxy.replace(target)
92
90
  end
93
- target
91
+ proxy
94
92
  end
95
93
  end
96
94
  end
@@ -20,6 +20,7 @@ module Mongoid #:nodoc
20
20
  include Mongoid::Fields
21
21
  include Mongoid::Hierarchy
22
22
  include Mongoid::Indexes
23
+ include Mongoid::JSON
23
24
  include Mongoid::Keys
24
25
  include Mongoid::Matchers
25
26
  include Mongoid::Memoization
@@ -7,6 +7,7 @@ module Mongoid #:nodoc
7
7
 
8
8
  attr_accessor \
9
9
  :allow_dynamic_fields,
10
+ :include_root_in_json,
10
11
  :reconnect_time,
11
12
  :parameterize_keys,
12
13
  :persist_in_safe_mode,
@@ -74,12 +75,10 @@ module Mongoid #:nodoc
74
75
  # The master +Mongo::DB+
75
76
  def master
76
77
  raise Errors::InvalidDatabase.new(nil) unless @master
77
-
78
78
  if @reconnect
79
79
  @reconnect = false
80
80
  reconnect!
81
81
  end
82
-
83
82
  @master
84
83
  end
85
84
 
@@ -193,6 +192,7 @@ module Mongoid #:nodoc
193
192
  # <tt>config.reset</tt>
194
193
  def reset
195
194
  @allow_dynamic_fields = true
195
+ @include_root_in_json = false
196
196
  @parameterize_keys = true
197
197
  @persist_in_safe_mode = false
198
198
  @raise_not_found_error = true
@@ -7,21 +7,6 @@ module Mongoid #:nodoc:
7
7
 
8
8
  attr_accessor :association_name
9
9
  attr_reader :new_record
10
-
11
- unless self.instance_of?(Class) and self.name == ""
12
- (@@descendants ||= {})[self] = :seen
13
- end
14
- end
15
-
16
- class << self
17
-
18
- # Returns all classes that have included Mongoid::Document.
19
- #
20
- # This will not get subclasses of the top level models, for those we will
21
- # use Class.descendents in the rake task for indexes.
22
- def descendants
23
- (@@descendants ||= {}).keys
24
- end
25
10
  end
26
11
 
27
12
  module ClassMethods #:nodoc:
@@ -31,8 +16,8 @@ module Mongoid #:nodoc:
31
16
  # This method must remain in the +Document+ module, even though its
32
17
  # behavior affects items in the Hierarchy module.
33
18
  def inherited(subclass)
34
- super(subclass)
35
19
  self.hereditary = true
20
+ super
36
21
  end
37
22
 
38
23
  # Instantiate a new object, only when loaded from the database or when
@@ -114,4 +114,8 @@ end
114
114
 
115
115
  class BSON::ObjectID #:nodoc
116
116
  extend Mongoid::Extensions::ObjectID::Conversions
117
+
118
+ def as_json(options = nil)
119
+ to_s
120
+ end
117
121
  end
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ # This module is for hooking in to +ActiveModel+s serialization to let
4
+ # configuring the ability to include the root in JSON happen from the Mongoid
5
+ # config.
6
+ module JSON
7
+ extend ActiveSupport::Concern
8
+
9
+ # We need to redefine where the JSON configuration is getting defined,
10
+ # similar to +ActiveRecord+.
11
+ included do
12
+ undef_method :include_root_in_json
13
+ delegate :include_root_in_json, :to => ::Mongoid
14
+ end
15
+ end
16
+ end
@@ -26,7 +26,7 @@ module Mongoid #:nodoc:
26
26
  #
27
27
  # <tt>document.destroy</tt>
28
28
  def destroy(options = {})
29
- run_callbacks(:destroy) { self.destroyed = true if _remove(options) }
29
+ run_callbacks(:destroy) { _remove(options) }
30
30
  end
31
31
 
32
32
  # Insert a new +Document+ into the database. Will return the document
@@ -47,7 +47,10 @@ module Mongoid #:nodoc:
47
47
  #
48
48
  # TODO: Will get rid of other #remove once observable pattern killed.
49
49
  def _remove(options = {})
50
- Remove.new(self, options).persist
50
+ if Remove.new(self, options).persist
51
+ self.destroyed = true
52
+ cascading_remove!
53
+ end; true
51
54
  end
52
55
 
53
56
  alias :delete :_remove
@@ -131,6 +134,19 @@ module Mongoid #:nodoc:
131
134
  # <tt>document.save</tt>
132
135
  alias :save :upsert
133
136
 
137
+ protected
138
+
139
+ # Perform all cascading deletes or destroys.
140
+ def cascading_remove!
141
+ cascades.each do |name, option|
142
+ association = send(name)
143
+ if association
144
+ documents = association.target.to_a
145
+ documents.each { |doc| doc.send(option) }
146
+ end
147
+ end
148
+ end
149
+
134
150
  module ClassMethods #:nodoc:
135
151
 
136
152
  # Create a new +Document+. This will instantiate a new document and
@@ -35,7 +35,7 @@ module Mongoid #:nodoc:
35
35
  ).persist
36
36
  else
37
37
  @collection.remove({ :_id => @document.id }, @options)
38
- end
38
+ end; true
39
39
  end
40
40
  end
41
41
  end
@@ -57,7 +57,18 @@ namespace :db do
57
57
  if not Rake::Task.task_defined?("db:create_indexes")
58
58
  desc 'Create the indexes defined on your mongoid models'
59
59
  task :create_indexes => :environment do
60
- ::Rails::Mongoid.index_children(Mongoid::Document.descendants)
60
+ documents = []
61
+ Dir.glob("app/models/**/*.rb").sort.each do |file|
62
+ model = file.match(/\/(\w+).rb$/)[1]
63
+ klass = model.classify.constantize
64
+ begin
65
+ documents << klass unless klass.embedded
66
+ rescue => e
67
+ # Just for non-mongoid objects that dont have the embedded
68
+ # attribute at the class level.
69
+ end
70
+ end
71
+ ::Rails::Mongoid.index_children(documents)
61
72
  end
62
73
  end
63
74
 
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Mongoid #:nodoc
3
- VERSION = "2.0.0.beta.14"
3
+ VERSION = "2.0.0.beta.15"
4
4
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid
3
3
  version: !ruby/object:Gem::Version
4
- hash: 62196479
4
+ hash: 62196477
5
5
  prerelease: true
6
6
  segments:
7
7
  - 2
8
8
  - 0
9
9
  - 0
10
10
  - beta
11
- - 14
12
- version: 2.0.0.beta.14
11
+ - 15
12
+ version: 2.0.0.beta.15
13
13
  platform: ruby
14
14
  authors:
15
15
  - Durran Jordan
@@ -17,7 +17,7 @@ autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
19
 
20
- date: 2010-07-27 00:00:00 -04:00
20
+ date: 2010-07-29 00:00:00 -04:00
21
21
  default_executable:
22
22
  dependencies:
23
23
  - !ruby/object:Gem::Dependency
@@ -253,6 +253,7 @@ files:
253
253
  - lib/mongoid/indexes.rb
254
254
  - lib/mongoid/javascript/functions.yml
255
255
  - lib/mongoid/javascript.rb
256
+ - lib/mongoid/json.rb
256
257
  - lib/mongoid/keys.rb
257
258
  - lib/mongoid/logger.rb
258
259
  - lib/mongoid/matchers/all.rb