mongoid 0.9.8 → 0.9.9

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 (34) hide show
  1. data/README.textile +5 -4
  2. data/VERSION +1 -1
  3. data/lib/mongoid.rb +3 -28
  4. data/lib/mongoid/associations.rb +63 -44
  5. data/lib/mongoid/associations/{relates_to_one.rb → belongs_to_related.rb} +4 -4
  6. data/lib/mongoid/associations/has_many.rb +26 -12
  7. data/lib/mongoid/associations/has_many_related.rb +100 -0
  8. data/lib/mongoid/associations/has_one.rb +13 -2
  9. data/lib/mongoid/associations/{relates_to_many.rb → has_one_related.rb} +34 -9
  10. data/lib/mongoid/attributes.rb +108 -8
  11. data/lib/mongoid/commands.rb +3 -11
  12. data/lib/mongoid/commands/save.rb +2 -6
  13. data/lib/mongoid/document.rb +6 -70
  14. data/lib/mongoid/errors.rb +34 -0
  15. data/mongoid.gemspec +14 -11
  16. data/spec/integration/mongoid/associations_spec.rb +19 -14
  17. data/spec/spec_helper.rb +6 -3
  18. data/spec/unit/mongoid/associations/belongs_to_related_spec.rb +112 -0
  19. data/spec/unit/mongoid/associations/has_many_related_spec.rb +292 -0
  20. data/spec/unit/mongoid/associations/has_many_spec.rb +17 -0
  21. data/spec/unit/mongoid/associations/has_one_related_spec.rb +130 -0
  22. data/spec/unit/mongoid/associations/has_one_spec.rb +53 -0
  23. data/spec/unit/mongoid/associations_spec.rb +36 -8
  24. data/spec/unit/mongoid/attributes_spec.rb +218 -0
  25. data/spec/unit/mongoid/commands/save_spec.rb +4 -2
  26. data/spec/unit/mongoid/commands_spec.rb +4 -17
  27. data/spec/unit/mongoid/criteria_spec.rb +0 -5
  28. data/spec/unit/mongoid/document_spec.rb +26 -156
  29. data/spec/unit/mongoid/errors_spec.rb +87 -0
  30. metadata +14 -11
  31. data/lib/mongoid/commands/quick_save.rb +0 -19
  32. data/spec/unit/mongoid/associations/relates_to_many_spec.rb +0 -76
  33. data/spec/unit/mongoid/associations/relates_to_one_spec.rb +0 -112
  34. data/spec/unit/mongoid/commands/quick_save_spec.rb +0 -24
@@ -4,7 +4,7 @@ module Mongoid #:nodoc:
4
4
  class HasOne #:nodoc:
5
5
 
6
6
  delegate :==, :to => :document
7
- attr_reader :document, :parent, :options
7
+ attr_reader :association_name, :document, :parent, :options
8
8
 
9
9
  # Build a new object for the association.
10
10
  def build(attributes)
@@ -32,7 +32,7 @@ module Mongoid #:nodoc:
32
32
  # attributes: The attributes of the decorated object.
33
33
  # options: The association options.
34
34
  def initialize(document, attributes, options)
35
- @parent, @options = document, options
35
+ @parent, @options, @association_name = document, options, options.name
36
36
  unless attributes.nil?
37
37
  @document = attributes.assimilate(@parent, @options)
38
38
  end
@@ -43,6 +43,17 @@ module Mongoid #:nodoc:
43
43
  @document.send(name, *args)
44
44
  end
45
45
 
46
+ # Used for setting the association via a nested attributes setter on the
47
+ # parent +Document+.
48
+ def nested_build(attributes)
49
+ build(attributes)
50
+ end
51
+
52
+ # Need to override here for when the underlying document is nil.
53
+ def valid?
54
+ @document ? @document.valid? : false
55
+ end
56
+
46
57
  class << self
47
58
  # Preferred method of instantiating a new +HasOne+, since nil values
48
59
  # will be handled properly.
@@ -1,7 +1,26 @@
1
1
  # encoding: utf-8
2
2
  module Mongoid #:nodoc:
3
3
  module Associations #:nodoc:
4
- class RelatesToMany < DelegateClass(Array) #:nodoc:
4
+ class HasOneRelated #:nodoc:
5
+
6
+ delegate :==, :nil?, :to => :document
7
+ attr_reader :klass, :document
8
+
9
+ # Builds a new Document and sets it as the association.
10
+ #
11
+ # Returns the newly created object.
12
+ def build(attributes)
13
+ @document = @klass.instantiate(attributes)
14
+ @document.send("#{@foreign_key}=", @parent.id)
15
+ end
16
+
17
+ # Builds a new Document and sets it as the association, then saves the
18
+ # newly created document.
19
+ #
20
+ # Returns the newly created object.
21
+ def create(attributes)
22
+ build(attributes); @document.save; @document
23
+ end
5
24
 
6
25
  # Initializing a related association only requires looking up the objects
7
26
  # by their ids.
@@ -11,9 +30,14 @@ module Mongoid #:nodoc:
11
30
  # document: The +Document+ that contains the relationship.
12
31
  # options: The association +Options+.
13
32
  def initialize(document, options)
14
- name = document.class.to_s.foreign_key
15
- @documents = options.klass.all(:conditions => { name => document.id })
16
- super(@documents)
33
+ @parent, @klass = document, options.klass
34
+ @foreign_key = document.class.to_s.foreign_key
35
+ @document = @klass.first(:conditions => { @foreign_key => @parent.id })
36
+ end
37
+
38
+ # Delegate all missing methods over to the +Document+.
39
+ def method_missing(name, *args)
40
+ @document.send(name, *args)
17
41
  end
18
42
 
19
43
  class << self
@@ -29,7 +53,7 @@ module Mongoid #:nodoc:
29
53
 
30
54
  # Returns the macro used to create the association.
31
55
  def macro
32
- :relates_to_many
56
+ :has_one_related
33
57
  end
34
58
 
35
59
  # Perform an update of the relationship of the parent and child. This
@@ -37,16 +61,17 @@ module Mongoid #:nodoc:
37
61
  #
38
62
  # Options:
39
63
  #
40
- # related: The related object
41
- # parent: The parent +Document+ to update.
64
+ # related: The related object to update.
65
+ # document: The parent +Document+.
42
66
  # options: The association +Options+
43
67
  #
44
68
  # Example:
45
69
  #
46
- # <tt>RelatesToOne.update(game, person, options)</tt>
70
+ # <tt>HasManyToRelated.update(game, person, options)</tt>
47
71
  def update(related, document, options)
48
72
  name = document.class.to_s.underscore
49
- related.each { |child| child.send("#{name}=", document) }
73
+ related.send("#{name}=", document)
74
+ related
50
75
  end
51
76
  end
52
77
 
@@ -1,13 +1,113 @@
1
1
  # encoding: utf-8
2
2
  module Mongoid #:nodoc:
3
- module Attributes #:nodoc:
4
- # Process the provided attributes casting them to their proper values if a
5
- # field exists for them on the +Document+. This will be limited to only the
6
- # attributes provided in the suppied +Hash+ so that no extra nil values get
7
- # put into the document's attributes.
8
- def process(attrs = {})
9
- attrs.each_pair do |key, value|
10
- send("#{key}=", value)
3
+ module Attributes
4
+ def self.included(base)
5
+ base.class_eval do
6
+ include InstanceMethods
7
+ extend ClassMethods
8
+ end
9
+ end
10
+ module InstanceMethods
11
+ # Process the provided attributes casting them to their proper values if a
12
+ # field exists for them on the +Document+. This will be limited to only the
13
+ # attributes provided in the suppied +Hash+ so that no extra nil values get
14
+ # put into the document's attributes.
15
+ def process(attrs = {})
16
+ attrs.each_pair do |key, value|
17
+ send("#{key}=", value)
18
+ end
19
+ end
20
+
21
+ # Read a value from the +Document+ attributes. If the value does not exist
22
+ # it will return nil.
23
+ #
24
+ # Options:
25
+ #
26
+ # name: The name of the attribute to get.
27
+ #
28
+ # Example:
29
+ #
30
+ # <tt>person.read_attribute(:title)</tt>
31
+ def read_attribute(name)
32
+ fields[name].get(@attributes[name])
33
+ end
34
+
35
+ # Remove a value from the +Document+ attributes. If the value does not exist
36
+ # it will fail gracefully.
37
+ #
38
+ # Options:
39
+ #
40
+ # name: The name of the attribute to remove.
41
+ #
42
+ # Example:
43
+ #
44
+ # <tt>person.remove_attribute(:title)</tt>
45
+ def remove_attribute(name)
46
+ @attributes.delete(name)
47
+ end
48
+
49
+ # Write a single attribute to the +Document+ attribute +Hash+. This will
50
+ # also fire the before and after update callbacks, and perform any
51
+ # necessary typecasting.
52
+ #
53
+ # Options:
54
+ #
55
+ # name: The name of the attribute to update.
56
+ # value: The value to set for the attribute.
57
+ #
58
+ # Example:
59
+ #
60
+ # <tt>person.write_attribute(:title, "Mr.")</tt>
61
+ #
62
+ # This will also cause the observing +Document+ to notify it's parent if
63
+ # there is any.
64
+ def write_attribute(name, value)
65
+ run_callbacks(:before_update)
66
+ @attributes[name] = fields[name].set(value)
67
+ run_callbacks(:after_update)
68
+ notify
69
+ end
70
+
71
+ # Writes the supplied attributes +Hash+ to the +Document+. This will only
72
+ # overwrite existing attributes if they are present in the new +Hash+, all
73
+ # others will be preserved.
74
+ #
75
+ # Options:
76
+ #
77
+ # attrs: The +Hash+ of new attributes to set on the +Document+
78
+ #
79
+ # Example:
80
+ #
81
+ # <tt>person.write_attributes(:title => "Mr.")</tt>
82
+ #
83
+ # This will also cause the observing +Document+ to notify it's parent if
84
+ # there is any.
85
+ def write_attributes(attrs)
86
+ process(attrs)
87
+ notify
88
+ end
89
+ end
90
+
91
+ module ClassMethods
92
+ # Defines attribute setters for the associations specified by the names.
93
+ # This will work for a has one or has many association.
94
+ #
95
+ # Example:
96
+ #
97
+ # class Person < Mongoid::Document
98
+ # has_one :name
99
+ # has_many :addresses
100
+ #
101
+ # accepts_nested_attributes_for :name, :addresses
102
+ # end
103
+ def accepts_nested_attributes_for(*args)
104
+ args.flatten.each do |name|
105
+ define_method("#{name}_attributes=") do |attrs|
106
+ association = send(name)
107
+ update(association, true)
108
+ association.nested_build(attrs)
109
+ end
110
+ end
11
111
  end
12
112
  end
13
113
  end
@@ -5,7 +5,6 @@ require "mongoid/commands/delete_all"
5
5
  require "mongoid/commands/destroy"
6
6
  require "mongoid/commands/destroy_all"
7
7
  require "mongoid/commands/save"
8
- require "mongoid/commands/quick_save"
9
8
  require "mongoid/commands/validate"
10
9
 
11
10
  module Mongoid #:nodoc:
@@ -56,19 +55,12 @@ module Mongoid #:nodoc:
56
55
  # returns false then a +ValidationError+ will be raised.
57
56
  def save!
58
57
  if new_record?
59
- return Create.execute(self) || (raise ValidationsError.new(self.errors.full_messages))
58
+ return Create.execute(self) || (raise Errors::Validations.new(self.errors))
60
59
  else
61
- return Save.execute(self) || (raise ValidationsError.new(self.errors.full_messages))
60
+ return Save.execute(self) || (raise Errors::Validations.new(self.errors))
62
61
  end
63
62
  end
64
63
 
65
- # Performs a save with no validations and no callbacks. This is used in
66
- # relational association saves, and is not recommended for use by
67
- # anything else.
68
- def quick_save
69
- QuickSave.execute(self)
70
- end
71
-
72
64
  # Update the attributes of the +Document+. Will call save after the
73
65
  # attributes have been updated.
74
66
  def update_attributes(attrs = {})
@@ -97,7 +89,7 @@ module Mongoid #:nodoc:
97
89
  # validation.
98
90
  def create!(attributes = {})
99
91
  document = Create.execute(new(attributes))
100
- raise ValidationsError.new(self.errors.full_messages) unless document.errors.empty?
92
+ raise Errors::Validations.new(self.errors) unless document.errors.empty?
101
93
  return document
102
94
  end
103
95
 
@@ -14,12 +14,8 @@ module Mongoid #:nodoc:
14
14
  return false unless Validate.execute(doc)
15
15
  doc.run_callbacks :before_save
16
16
  parent = doc.parent
17
- if parent
18
- Save.execute(parent)
19
- else
20
- collection = doc.collection
21
- collection ? collection.save(doc.attributes) : raise(MissingParentError.new(doc))
22
- end
17
+ doc.new_record = false
18
+ parent ? Save.execute(parent) : doc.collection.save(doc.attributes)
23
19
  doc.run_callbacks :after_save
24
20
  return true
25
21
  end
@@ -21,7 +21,7 @@ module Mongoid #:nodoc:
21
21
  #
22
22
  # Returns: <tt>Mongo::Collection</tt>
23
23
  def collection
24
- return nil if embedded?
24
+ raise Errors::InvalidCollection.new(self) if embedded?
25
25
  @collection_name ||= self.to_s.demodulize.tableize
26
26
  @collection ||= Mongoid.database.collection(@collection_name)
27
27
  end
@@ -195,6 +195,11 @@ module Mongoid #:nodoc:
195
195
  @new_record == true
196
196
  end
197
197
 
198
+ # Sets the new_record boolean - used after document is saved.
199
+ def new_record=(saved)
200
+ @new_record = saved
201
+ end
202
+
198
203
  # Set the changed state of the +Document+ then notify observers that it has changed.
199
204
  #
200
205
  # Example:
@@ -223,34 +228,6 @@ module Mongoid #:nodoc:
223
228
  add_observer(object)
224
229
  end
225
230
 
226
- # Read a value from the +Document+ attributes. If the value does not exist
227
- # it will return nil.
228
- #
229
- # Options:
230
- #
231
- # name: The name of the attribute to get.
232
- #
233
- # Example:
234
- #
235
- # <tt>person.read_attribute(:title)</tt>
236
- def read_attribute(name)
237
- fields[name].get(@attributes[name])
238
- end
239
-
240
- # Remove a value from the +Document+ attributes. If the value does not exist
241
- # it will fail gracefully.
242
- #
243
- # Options:
244
- #
245
- # name: The name of the attribute to remove.
246
- #
247
- # Example:
248
- #
249
- # <tt>person.remove_attribute(:title)</tt>
250
- def remove_attribute(name)
251
- @attributes.delete(name)
252
- end
253
-
254
231
  # Reloads the +Document+ attributes from the database.
255
232
  def reload
256
233
  @attributes = collection.find_one(:_id => id).with_indifferent_access
@@ -290,47 +267,6 @@ module Mongoid #:nodoc:
290
267
  notify
291
268
  end
292
269
 
293
- # Write a single attribute to the +Document+ attribute +Hash+. This will
294
- # also fire the before and after update callbacks, and perform any
295
- # necessary typecasting.
296
- #
297
- # Options:
298
- #
299
- # name: The name of the attribute to update.
300
- # value: The value to set for the attribute.
301
- #
302
- # Example:
303
- #
304
- # <tt>person.write_attribute(:title, "Mr.")</tt>
305
- #
306
- # This will also cause the observing +Document+ to notify it's parent if
307
- # there is any.
308
- def write_attribute(name, value)
309
- run_callbacks(:before_update)
310
- @attributes[name] = fields[name].set(value)
311
- run_callbacks(:after_update)
312
- notify
313
- end
314
-
315
- # Writes the supplied attributes +Hash+ to the +Document+. This will only
316
- # overwrite existing attributes if they are present in the new +Hash+, all
317
- # others will be preserved.
318
- #
319
- # Options:
320
- #
321
- # attrs: The +Hash+ of new attributes to set on the +Document+
322
- #
323
- # Example:
324
- #
325
- # <tt>person.write_attributes(:title => "Mr.")</tt>
326
- #
327
- # This will also cause the observing +Document+ to notify it's parent if
328
- # there is any.
329
- def write_attributes(attrs)
330
- process(attrs)
331
- notify
332
- end
333
-
334
270
  protected
335
271
  def generate_key
336
272
  if primary_key
@@ -0,0 +1,34 @@
1
+ module Mongoid #:nodoc
2
+ module Errors #:nodoc
3
+
4
+ # Raised when invalid options are passed into a constructor.
5
+ class InvalidOptions < RuntimeError; end
6
+
7
+ # Raised when the database connection has not been set up.
8
+ class InvalidDatabase < RuntimeError; end
9
+
10
+ # Raised when a persisence method ending in ! fails validation.
11
+ class Validations < RuntimeError
12
+ def initialize(errors)
13
+ @errors = errors
14
+ end
15
+ def message
16
+ "Validation failed: #{@errors.full_messages}"
17
+ end
18
+ end
19
+
20
+ # This error is raised when trying to access a Mongo::Collection from an
21
+ # embedded document.
22
+ class InvalidCollection < RuntimeError
23
+ def initialize(klass)
24
+ @klass = klass
25
+ end
26
+ def message
27
+ "Access to the collection for #{@klass.name} is not allowed " +
28
+ "since it is an embedded document, please access a collection from " +
29
+ "the root document"
30
+ end
31
+ end
32
+
33
+ end
34
+ end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{mongoid}
8
- s.version = "0.9.8"
8
+ s.version = "0.9.9"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Durran Jordan"]
12
- s.date = %q{2009-12-12}
12
+ s.date = %q{2009-12-13}
13
13
  s.email = %q{durran@gmail.com}
14
14
  s.extra_rdoc_files = [
15
15
  "README.textile"
@@ -24,11 +24,12 @@ Gem::Specification.new do |s|
24
24
  "lib/mongoid.rb",
25
25
  "lib/mongoid/associations.rb",
26
26
  "lib/mongoid/associations/belongs_to.rb",
27
+ "lib/mongoid/associations/belongs_to_related.rb",
27
28
  "lib/mongoid/associations/has_many.rb",
29
+ "lib/mongoid/associations/has_many_related.rb",
28
30
  "lib/mongoid/associations/has_one.rb",
31
+ "lib/mongoid/associations/has_one_related.rb",
29
32
  "lib/mongoid/associations/options.rb",
30
- "lib/mongoid/associations/relates_to_many.rb",
31
- "lib/mongoid/associations/relates_to_one.rb",
32
33
  "lib/mongoid/attributes.rb",
33
34
  "lib/mongoid/commands.rb",
34
35
  "lib/mongoid/commands/create.rb",
@@ -36,12 +37,12 @@ Gem::Specification.new do |s|
36
37
  "lib/mongoid/commands/delete_all.rb",
37
38
  "lib/mongoid/commands/destroy.rb",
38
39
  "lib/mongoid/commands/destroy_all.rb",
39
- "lib/mongoid/commands/quick_save.rb",
40
40
  "lib/mongoid/commands/save.rb",
41
41
  "lib/mongoid/commands/validate.rb",
42
42
  "lib/mongoid/criteria.rb",
43
43
  "lib/mongoid/document.rb",
44
44
  "lib/mongoid/dynamic_finder.rb",
45
+ "lib/mongoid/errors.rb",
45
46
  "lib/mongoid/extensions.rb",
46
47
  "lib/mongoid/extensions/array/accessors.rb",
47
48
  "lib/mongoid/extensions/array/assimilation.rb",
@@ -71,12 +72,13 @@ Gem::Specification.new do |s|
71
72
  "spec/integration/mongoid/document_spec.rb",
72
73
  "spec/spec.opts",
73
74
  "spec/spec_helper.rb",
75
+ "spec/unit/mongoid/associations/belongs_to_related_spec.rb",
74
76
  "spec/unit/mongoid/associations/belongs_to_spec.rb",
77
+ "spec/unit/mongoid/associations/has_many_related_spec.rb",
75
78
  "spec/unit/mongoid/associations/has_many_spec.rb",
79
+ "spec/unit/mongoid/associations/has_one_related_spec.rb",
76
80
  "spec/unit/mongoid/associations/has_one_spec.rb",
77
81
  "spec/unit/mongoid/associations/options_spec.rb",
78
- "spec/unit/mongoid/associations/relates_to_many_spec.rb",
79
- "spec/unit/mongoid/associations/relates_to_one_spec.rb",
80
82
  "spec/unit/mongoid/associations_spec.rb",
81
83
  "spec/unit/mongoid/attributes_spec.rb",
82
84
  "spec/unit/mongoid/commands/create_spec.rb",
@@ -84,13 +86,13 @@ Gem::Specification.new do |s|
84
86
  "spec/unit/mongoid/commands/delete_spec.rb",
85
87
  "spec/unit/mongoid/commands/destroy_all_spec.rb",
86
88
  "spec/unit/mongoid/commands/destroy_spec.rb",
87
- "spec/unit/mongoid/commands/quick_save_spec.rb",
88
89
  "spec/unit/mongoid/commands/save_spec.rb",
89
90
  "spec/unit/mongoid/commands/validate_spec.rb",
90
91
  "spec/unit/mongoid/commands_spec.rb",
91
92
  "spec/unit/mongoid/criteria_spec.rb",
92
93
  "spec/unit/mongoid/document_spec.rb",
93
94
  "spec/unit/mongoid/dynamic_finder_spec.rb",
95
+ "spec/unit/mongoid/errors_spec.rb",
94
96
  "spec/unit/mongoid/extensions/array/accessors_spec.rb",
95
97
  "spec/unit/mongoid/extensions/array/assimilation_spec.rb",
96
98
  "spec/unit/mongoid/extensions/array/conversions_spec.rb",
@@ -123,12 +125,13 @@ Gem::Specification.new do |s|
123
125
  "spec/integration/mongoid/associations_spec.rb",
124
126
  "spec/integration/mongoid/document_spec.rb",
125
127
  "spec/spec_helper.rb",
128
+ "spec/unit/mongoid/associations/belongs_to_related_spec.rb",
126
129
  "spec/unit/mongoid/associations/belongs_to_spec.rb",
130
+ "spec/unit/mongoid/associations/has_many_related_spec.rb",
127
131
  "spec/unit/mongoid/associations/has_many_spec.rb",
132
+ "spec/unit/mongoid/associations/has_one_related_spec.rb",
128
133
  "spec/unit/mongoid/associations/has_one_spec.rb",
129
134
  "spec/unit/mongoid/associations/options_spec.rb",
130
- "spec/unit/mongoid/associations/relates_to_many_spec.rb",
131
- "spec/unit/mongoid/associations/relates_to_one_spec.rb",
132
135
  "spec/unit/mongoid/associations_spec.rb",
133
136
  "spec/unit/mongoid/attributes_spec.rb",
134
137
  "spec/unit/mongoid/commands/create_spec.rb",
@@ -136,13 +139,13 @@ Gem::Specification.new do |s|
136
139
  "spec/unit/mongoid/commands/delete_spec.rb",
137
140
  "spec/unit/mongoid/commands/destroy_all_spec.rb",
138
141
  "spec/unit/mongoid/commands/destroy_spec.rb",
139
- "spec/unit/mongoid/commands/quick_save_spec.rb",
140
142
  "spec/unit/mongoid/commands/save_spec.rb",
141
143
  "spec/unit/mongoid/commands/validate_spec.rb",
142
144
  "spec/unit/mongoid/commands_spec.rb",
143
145
  "spec/unit/mongoid/criteria_spec.rb",
144
146
  "spec/unit/mongoid/document_spec.rb",
145
147
  "spec/unit/mongoid/dynamic_finder_spec.rb",
148
+ "spec/unit/mongoid/errors_spec.rb",
146
149
  "spec/unit/mongoid/extensions/array/accessors_spec.rb",
147
150
  "spec/unit/mongoid/extensions/array/assimilation_spec.rb",
148
151
  "spec/unit/mongoid/extensions/array/conversions_spec.rb",