mongoid 2.0.0.rc.5 → 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 (50) hide show
  1. data/{MIT_LICENSE → LICENSE} +0 -0
  2. data/README.rdoc +2 -7
  3. data/lib/config/locales/bg.yml +3 -1
  4. data/lib/config/locales/de.yml +3 -0
  5. data/lib/config/locales/en.yml +3 -0
  6. data/lib/config/locales/es.yml +3 -0
  7. data/lib/config/locales/fr.yml +4 -1
  8. data/lib/config/locales/hu.yml +3 -1
  9. data/lib/config/locales/it.yml +3 -0
  10. data/lib/config/locales/kr.yml +3 -0
  11. data/lib/config/locales/nl.yml +3 -0
  12. data/lib/config/locales/pl.yml +3 -0
  13. data/lib/config/locales/pt-br.yml +3 -0
  14. data/lib/config/locales/pt.yml +3 -0
  15. data/lib/config/locales/ro.yml +3 -1
  16. data/lib/config/locales/sv.yml +4 -1
  17. data/lib/config/locales/zh-CN.yml +3 -0
  18. data/lib/mongoid.rb +1 -0
  19. data/lib/mongoid/attributes.rb +1 -1
  20. data/lib/mongoid/callbacks.rb +3 -17
  21. data/lib/mongoid/components.rb +1 -1
  22. data/lib/mongoid/contexts/enumerable.rb +17 -0
  23. data/lib/mongoid/contexts/mongo.rb +9 -6
  24. data/lib/mongoid/criterion/inspection.rb +1 -3
  25. data/lib/mongoid/errors.rb +1 -0
  26. data/lib/mongoid/errors/unsaved_document.rb +23 -0
  27. data/lib/mongoid/extras.rb +1 -1
  28. data/lib/mongoid/fields.rb +81 -15
  29. data/lib/mongoid/finders.rb +1 -1
  30. data/lib/mongoid/persistence.rb +16 -0
  31. data/lib/mongoid/railtie.rb +6 -11
  32. data/lib/mongoid/relations/accessors.rb +1 -1
  33. data/lib/mongoid/relations/builders/nested_attributes/many.rb +3 -3
  34. data/lib/mongoid/relations/builders/nested_attributes/one.rb +2 -2
  35. data/lib/mongoid/relations/builders/referenced/many_to_many.rb +1 -1
  36. data/lib/mongoid/relations/cascading.rb +1 -1
  37. data/lib/mongoid/relations/embedded/many.rb +1 -1
  38. data/lib/mongoid/relations/macros.rb +1 -1
  39. data/lib/mongoid/relations/many.rb +20 -0
  40. data/lib/mongoid/relations/metadata.rb +1 -1
  41. data/lib/mongoid/relations/nested_builder.rb +18 -0
  42. data/lib/mongoid/relations/polymorphic.rb +1 -1
  43. data/lib/mongoid/relations/referenced/many.rb +52 -2
  44. data/lib/mongoid/relations/referenced/many_to_many.rb +35 -0
  45. data/lib/mongoid/safety.rb +1 -1
  46. data/lib/mongoid/serialization.rb +99 -0
  47. data/lib/mongoid/timestamps.rb +1 -1
  48. data/lib/mongoid/validations.rb +47 -36
  49. data/lib/mongoid/version.rb +1 -1
  50. metadata +11 -11
File without changes
@@ -1,8 +1,3 @@
1
- = PLEASE READ (03 JAN 2011)
2
-
3
- USERS CURRENTLY POINTED AT master, PLEASE MOVE TO safe_master UNTIL
4
- FURTHER NOTICE.
5
-
6
1
  = Overview
7
2
 
8
3
  == About Mongoid
@@ -16,7 +11,7 @@ Mongoid is an ODM (Object-Document-Mapper) framework for MongoDB in Ruby.
16
11
 
17
12
  == Compatibility
18
13
 
19
- Mongoid is developed against Ruby 1.8.7, 1.9.1, 1.9.2, and REE.
14
+ Mongoid is developed against Ruby 1.8.7, 1.9.2, and REE.
20
15
 
21
16
  = Documentation
22
17
 
@@ -28,7 +23,7 @@ Please see the new Mongoid website for up-to-date documentation:
28
23
 
29
24
  = License
30
25
 
31
- Copyright (c) 2009, 2010 Durran Jordan
26
+ Copyright (c) 2009, 2010, 2011 Durran Jordan
32
27
 
33
28
  Permission is hereby granted, free of charge, to any person obtaining
34
29
  a copy of this software and associated documentation files (the
@@ -39,4 +39,6 @@ bg:
39
39
  references_many като масив.
40
40
  calling_document_find_with_nil_is_invalid:
41
41
  Извикването на Document#find със nil е невалидно
42
-
42
+ unsaved_document:
43
+ You cannot call create or create! through a relational association
44
+ relation (%{document}) who's parent (%{base}) is not already saved.
@@ -39,3 +39,6 @@ de:
39
39
  Es ist nicht erlaubt, inverse_of für diese Beziehung zu definieren.
40
40
  Diese Option kann nur für embedded_in oder references_many als Array
41
41
  verwendet werden.
42
+ unsaved_document:
43
+ You cannot call create or create! through a relational association
44
+ relation (%{document}) who's parent (%{base}) is not already saved.
@@ -40,3 +40,6 @@ en:
40
40
  use this option on embedded_in or references_many as array.
41
41
  calling_document_find_with_nil_is_invalid:
42
42
  Calling Document#find with nil is invalid
43
+ unsaved_document:
44
+ You cannot call create or create! through a relational association
45
+ relation (%{document}) who's parent (%{base}) is not already saved.
@@ -39,3 +39,6 @@ es:
39
39
  association_cant_have_inverse_of:
40
40
  No está permitido definir inverse_of en esta asociación. Utilice
41
41
  esta opción sólo en embedded_in o en references_many as array.
42
+ unsaved_document:
43
+ You cannot call create or create! through a relational association
44
+ relation (%{document}) who's parent (%{base}) is not already saved.
@@ -39,4 +39,7 @@ fr:
39
39
  pour les associations references_on ou references_many."
40
40
  association_cant_have_inverse_of:
41
41
  "Definir un inverse_of pour cette association n'est pas autorisé.
42
- Utilisez cette option seulement sur embedded_in ou references_many."
42
+ Utilisez cette option seulement sur embedded_in ou references_many."
43
+ unsaved_document:
44
+ You cannot call create or create! through a relational association
45
+ relation (%{document}) who's parent (%{base}) is not already saved.
@@ -42,4 +42,6 @@ hu:
42
42
  esetében használható.
43
43
  calling_document_find_with_nil_is_invalid:
44
44
  Document#find parancs nil érték esetében érvénytelen.
45
-
45
+ unsaved_document:
46
+ You cannot call create or create! through a relational association
47
+ relation (%{document}) who's parent (%{base}) is not already saved.
@@ -37,3 +37,6 @@ it:
37
37
  association_cant_have_inverse_of:
38
38
  Non è permesso definire un inverse_of in questa associazione.
39
39
  Usa questa opzione solo per embedded_in o references_many as array.
40
+ unsaved_document:
41
+ You cannot call create or create! through a relational association
42
+ relation (%{document}) who's parent (%{base}) is not already saved.
@@ -63,3 +63,6 @@ kr:
63
63
  #Defining an inverse_of on this association is not allowed. Only
64
64
  #use this option on embedded_in or references_many as array.
65
65
 
66
+ unsaved_document:
67
+ You cannot call create or create! through a relational association
68
+ relation (%{document}) who's parent (%{base}) is not already saved.
@@ -37,3 +37,6 @@ nl:
37
37
  alleen deze optie met embedded_in en references_many as array.
38
38
  calling_document_find_with_nil_is_invalid:
39
39
  Het is niet toegestaan om Document#find aan te roepen met de waarde nil.
40
+ unsaved_document:
41
+ You cannot call create or create! through a relational association
42
+ relation (%{document}) who's parent (%{base}) is not already saved.
@@ -37,3 +37,6 @@ pl:
37
37
  association_cant_have_inverse_of:
38
38
  Definiowanie inverse_of dla tej asocjacji jest niedozwolone. Używaj
39
39
  tej opcji tylko z embedded_in lub references_many as array.
40
+ unsaved_document:
41
+ You cannot call create or create! through a relational association
42
+ relation (%{document}) who's parent (%{base}) is not already saved.
@@ -38,3 +38,6 @@ pt-br:
38
38
  association_cant_have_inverse_of:
39
39
  A definição de inverse_of nesta associação não é permitida. Apenas
40
40
  use esta opção em embedded_in ou references_many as array.
41
+ unsaved_document:
42
+ You cannot call create or create! through a relational association
43
+ relation (%{document}) who's parent (%{base}) is not already saved.
@@ -38,3 +38,6 @@ pt:
38
38
  association_cant_have_inverse_of:
39
39
  A definição de inverse_of nesta associação não é permitida. Apenas
40
40
  use esta opção em embedded_in ou references_many como lista.
41
+ unsaved_document:
42
+ You cannot call create or create! through a relational association
43
+ relation (%{document}) who's parent (%{base}) is not already saved.
@@ -44,4 +44,6 @@ ro:
44
44
  tip embedded_in sau references_many as array.
45
45
  calling_document_find_with_nil_is_invalid:
46
46
  Folosirea metodei Document#find cu valoarea nil este invalidă.
47
-
47
+ unsaved_document:
48
+ You cannot call create or create! through a relational association
49
+ relation (%{document}) who's parent (%{base}) is not already saved.
@@ -37,4 +37,7 @@ sv:
37
37
  är endast giltigt för references_one eller references_many associationer.
38
38
  association_cant_have_inverse_of:
39
39
  Att definera inverse_of på denna association är inte tillåtet. Använd
40
- endast detta alternativ på embedded_in eller references_many as array.
40
+ endast detta alternativ på embedded_in eller references_many as array.
41
+ unsaved_document:
42
+ You cannot call create or create! through a relational association
43
+ relation (%{document}) who's parent (%{base}) is not already saved.
@@ -29,3 +29,6 @@ en:
29
29
  dependent => destroy|delete 选项只有在references_one或者references_many时候有效.
30
30
  association_cant_have_inverse_of:
31
31
  在当前的关联中,不允许定义inverse_of去,其只有在embedded_in或者references_many是数组的情况下使用
32
+ unsaved_document:
33
+ You cannot call create or create! through a relational association
34
+ relation (%{document}) who's parent (%{base}) is not already saved.
@@ -78,6 +78,7 @@ require "mongoid/persistence"
78
78
  require "mongoid/relations"
79
79
  require "mongoid/safety"
80
80
  require "mongoid/scope"
81
+ require "mongoid/serialization"
81
82
  require "mongoid/state"
82
83
  require "mongoid/timestamps"
83
84
  require "mongoid/validations"
@@ -62,7 +62,7 @@ module Mongoid #:nodoc:
62
62
  #
63
63
  # @return [ BSON::ObjectId, String ] The new id.
64
64
  def id=(new_id)
65
- @attributes["_id"] = new_id
65
+ @attributes["_id"] = _id_type.set(new_id)
66
66
  end
67
67
  alias :_id= :id=
68
68
 
@@ -4,24 +4,10 @@ module Mongoid #:nodoc:
4
4
  extend ActiveSupport::Concern
5
5
  included do
6
6
  extend ActiveModel::Callbacks
7
+ include ActiveModel::Validations::Callbacks
7
8
 
8
- define_model_callbacks \
9
- :create,
10
- :destroy,
11
- :initialize,
12
- :save,
13
- :update,
14
- :validation
15
- end
16
-
17
- # Determine if the document is valid.
18
- #
19
- # @example Is the document valid?
20
- # person.valid?
21
- #
22
- # @return [ true, false ] True if valid, false if not.
23
- def valid?(*)
24
- _run_validation_callbacks { super }
9
+ define_model_callbacks :initialize, :only => :after
10
+ define_model_callbacks :create, :destroy, :save, :update
25
11
  end
26
12
  end
27
13
  end
@@ -14,7 +14,6 @@ module Mongoid #:nodoc
14
14
 
15
15
  include ActiveModel::Conversion
16
16
  include ActiveModel::Naming
17
- include ActiveModel::Serialization
18
17
  include ActiveModel::MassAssignmentSecurity
19
18
  include ActiveModel::Serializers::JSON
20
19
  include ActiveModel::Serializers::Xml
@@ -38,6 +37,7 @@ module Mongoid #:nodoc
38
37
  include Mongoid::Persistence
39
38
  include Mongoid::Relations
40
39
  include Mongoid::Safety
40
+ include Mongoid::Serialization
41
41
  include Mongoid::State
42
42
  include Mongoid::Validations
43
43
  include Mongoid::Callbacks
@@ -168,6 +168,23 @@ module Mongoid #:nodoc:
168
168
  end
169
169
  end
170
170
 
171
+ # Very basic update that will perform a simple atomic $set of the
172
+ # attributes provided in the hash. Can be expanded to later for more
173
+ # robust functionality.
174
+ #
175
+ # @example Update all matching documents.
176
+ # context.update_all(:title => "Sir")
177
+ #
178
+ # @param [ Hash ] attributes The sets to perform.
179
+ #
180
+ # @since 2.0.0.rc.6
181
+ def update_all(attributes = nil)
182
+ iterate do |doc|
183
+ doc.update_attributes(attributes || {})
184
+ end
185
+ end
186
+ alias :update :update_all
187
+
171
188
  protected
172
189
  # Filters the documents against the criteria's selector
173
190
  def filter
@@ -55,15 +55,18 @@ module Mongoid #:nodoc:
55
55
 
56
56
  # Get the count of matching documents in the database for the context.
57
57
  #
58
- # Example:
58
+ # @example Get the count without skip and limit taken into consideration.
59
+ # context.count
59
60
  #
60
- # <tt>context.count</tt>
61
+ # @example Get the count with skip and limit applied.
62
+ # context.count(true)
61
63
  #
62
- # Returns:
64
+ # @param [Boolean] extras True to inclued previous skip/limit
65
+ # statements in the count; false to ignore them. Defaults to `false`.
63
66
  #
64
- # An +Integer+ count of documents.
65
- def count
66
- @count ||= klass.collection.find(selector, process_options).count
67
+ # @return [ Integer ] The count of documents.
68
+ def count(extras = false)
69
+ @count ||= klass.collection.find(selector, process_options).count(extras)
67
70
  end
68
71
 
69
72
  # Delete all the documents in the database matching the selector.
@@ -13,9 +13,7 @@ module Mongoid #:nodoc:
13
13
  def inspect
14
14
  "#<Mongoid::Criteria\n" <<
15
15
  " selector: #{selector.inspect},\n" <<
16
- " options: #{options.inspect},\n" <<
17
- " count: #{count.inspect},\n" <<
18
- " matching: #{entries.inspect}>\n"
16
+ " options: #{options.inspect}>\n"
19
17
  end
20
18
  end
21
19
  end
@@ -7,5 +7,6 @@ require "mongoid/errors/invalid_field"
7
7
  require "mongoid/errors/invalid_options"
8
8
  require "mongoid/errors/invalid_type"
9
9
  require "mongoid/errors/too_many_nested_attribute_records"
10
+ require "mongoid/errors/unsaved_document"
10
11
  require "mongoid/errors/unsupported_version"
11
12
  require "mongoid/errors/validations"
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc
3
+ module Errors #:nodoc
4
+
5
+ # Raised when attempting to call create or create! through a
6
+ # references_many when the parent document has not been saved. This
7
+ # prevents the child from getting presisted and immediately being orphaned.
8
+ class UnsavedDocument < MongoidError
9
+
10
+ attr_reader :base, :document
11
+
12
+ def initialize(base, document)
13
+ @base, @document = base, document
14
+ super(
15
+ translate(
16
+ "unsaved_document",
17
+ { :base => base.class.name, :document => document.class.name }
18
+ )
19
+ )
20
+ end
21
+ end
22
+ end
23
+ end
@@ -3,7 +3,7 @@ module Mongoid #:nodoc:
3
3
  module Extras #:nodoc:
4
4
  extend ActiveSupport::Concern
5
5
  included do
6
- class_inheritable_accessor :cached, :enslaved
6
+ class_attribute :cached, :enslaved
7
7
  self.cached = false
8
8
  self.enslaved = false
9
9
  delegate :cached?, :enslaved?, :to => "self.class"
@@ -1,46 +1,98 @@
1
1
  # encoding: utf-8
2
2
  module Mongoid #:nodoc
3
- module Fields #:nodoc
3
+
4
+ # This module defines behaviour for fields.
5
+ module Fields
4
6
  extend ActiveSupport::Concern
7
+
5
8
  included do
6
9
  # Set up the class attributes that must be available to all subclasses.
7
10
  # These include defaults, fields
8
- class_inheritable_accessor :fields
9
-
10
- self.fields = {}
11
11
  delegate :defaults, :fields, :to => "self.class"
12
12
  end
13
13
 
14
14
  module ClassMethods #:nodoc
15
+
15
16
  # Defines all the fields that are accessable on the Document
16
17
  # For each field that is defined, a getter and setter will be
17
18
  # added as an instance method to the Document.
18
19
  #
19
- # Options:
20
+ # @example Define a field.
21
+ # field :score, :type => Integer, :default => 0
20
22
  #
21
- # name: The name of the field, as a +Symbol+.
22
- # options: A +Hash+ of options to supply to the +Field+.
23
+ # @param [ Symbol ] name The name of the field.
24
+ # @param [ Hash ] options The options to pass to the field.
23
25
  #
24
- # Example:
25
- #
26
- # <tt>field :score, :default => 0</tt>
26
+ # @option options [ Class ] :type The type of the field.
27
+ # @option options [ String ] :label The label for the field.
28
+ # @option options [ Object, Proc ] :default The field's default
27
29
  def field(name, options = {})
28
30
  access = name.to_s
29
31
  set_field(access, options)
30
32
  attr_protected name if options[:accessible] == false
31
33
  end
32
34
 
33
- # Returns the default values for the fields on the document
35
+ # Return the fields for this class.
36
+ #
37
+ # @example Get the fields.
38
+ # Person.fields
39
+ #
40
+ # @return [ Hash ] The fields for this document.
41
+ #
42
+ # @since 2.0.0.rc.6
43
+ def fields
44
+ @fields ||= {}
45
+ end
46
+
47
+ # Set the fields for the class.
48
+ #
49
+ # @example Set the fields.
50
+ # Person.fields = fields
51
+ #
52
+ # @param [ Hash ] fields The hash of fields to set.
53
+ #
54
+ # @since 2.0.0.rc.6
55
+ def fields=(fields)
56
+ @fields = fields
57
+ end
58
+
59
+ # Returns the default values for the fields on the document.
60
+ #
61
+ # @example Get the defaults.
62
+ # Person.defaults
63
+ #
64
+ # @return [ Hash ] The field defaults.
34
65
  def defaults
35
- fields.inject({}) do |defs,(field_name,field)|
66
+ fields.inject({}) do |defs, (field_name,field)|
36
67
  next(defs) if field.default.nil?
37
68
  defs[field_name.to_s] = field.default
38
69
  defs
39
70
  end
40
71
  end
41
72
 
73
+ # When inheriting, we want to copy the fields from the parent class and
74
+ # set the on the child to start, mimicing the behaviour of the old
75
+ # class_inheritable_accessor that was deprecated in Rails edge.
76
+ #
77
+ # @example Inherit from this class.
78
+ # Person.inherited(Doctor)
79
+ #
80
+ # @param [ Class ] subclass The inheriting class.
81
+ #
82
+ # @since 2.0.0.rc.6
83
+ def inherited(subclass)
84
+ subclass.fields = fields.dup
85
+ end
86
+
42
87
  protected
88
+
43
89
  # Define a field attribute for the +Document+.
90
+ #
91
+ # @example Set the field.
92
+ # Person.set_field(:name, :default => "Test")
93
+ #
94
+ # @param [ Symbol ] name The name of the field.
95
+ # @param [ Hash ] options The hash of options.
44
96
  def set_field(name, options = {})
45
97
  meth = options.delete(:as) || name
46
98
  fields[name] = Field.new(name, options)
@@ -49,6 +101,16 @@ module Mongoid #:nodoc
49
101
  end
50
102
 
51
103
  # Create the field accessors.
104
+ #
105
+ # @example Generate the accessors.
106
+ # Person.create_accessors(:name, "name")
107
+ # person.name #=> returns the field
108
+ # person.name = "" #=> sets the field
109
+ # person.name? #=> Is the field present?
110
+ #
111
+ # @param [ Symbol ] name The name of the field.
112
+ # @param [ Symbol ] meth The name of the accessor.
113
+ # @param [ Hash ] options The options.
52
114
  def create_accessors(name, meth, options = {})
53
115
  generated_field_methods.module_eval do
54
116
  define_method(meth) { read_attribute(name) }
@@ -60,11 +122,15 @@ module Mongoid #:nodoc
60
122
  end
61
123
  end
62
124
 
125
+ # Include the field methods as a module, so they can be overridden.
126
+ #
127
+ # @example Include the fields.
128
+ # Person.generated_field_methods
63
129
  def generated_field_methods
64
130
  @generated_field_methods ||= begin
65
- mod = Module.new
66
- include mod
67
- mod
131
+ Module.new.tap do |mod|
132
+ include mod
133
+ end
68
134
  end
69
135
  end
70
136
  end
@@ -6,7 +6,7 @@ module Mongoid #:nodoc:
6
6
  # criteria.
7
7
  [ :all_in, :any_in, :any_of, :asc, :ascending, :avg, :desc, :descending,
8
8
  :excludes, :limit, :max, :min, :not_in, :only, :order_by,
9
- :skip, :sum, :where, :near ].each do |name|
9
+ :skip, :sum, :where, :update, :update_all, :near ].each do |name|
10
10
  define_method(name) do |*args|
11
11
  criteria.send(name, *args)
12
12
  end
@@ -86,6 +86,22 @@ module Mongoid #:nodoc:
86
86
  Update.new(self, options).persist
87
87
  end
88
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
+
89
105
  # Update the document attributes in the datbase.
90
106
  #
91
107
  # @example Update the document's attributes
@@ -67,18 +67,13 @@ module Rails #:nodoc:
67
67
  end
68
68
  end
69
69
 
70
- # After initialization we will attempt to connect to the database, if
71
- # we get an exception and can't find a mongoid.yml we will alert the user
72
- # to generate one.
73
- initializer "verify that mongoid is configured" do
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
74
73
  config.after_initialize do
75
- begin
76
- ::Mongoid.master
77
- rescue ::Mongoid::Errors::InvalidDatabase => e
78
- unless Rails.root.join("config", "mongoid.yml").file?
79
- puts "\nMongoid config not found. Create a config file at: config/mongoid.yml"
80
- puts "to generate one run: rails generate mongoid:config\n\n"
81
- end
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"
82
77
  end
83
78
  end
84
79
  end
@@ -143,7 +143,7 @@ module Mongoid # :nodoc:
143
143
  define_method("#{name}=") do |*args|
144
144
  object, options = args.first, options(args)
145
145
  variable = "@#{name}"
146
- if relation_exists?(name)
146
+ if relation_exists?(name) && !object.is_a?(Hash)
147
147
  set(name, ivar(name).substitute(object, options))
148
148
  else
149
149
  build(name, object, metadata, options.merge(:eager => true))
@@ -95,15 +95,15 @@ module Mongoid # :nodoc:
95
95
  #
96
96
  # Example:
97
97
  #
98
- # <tt>builder.process({ "_id" => 1, "street" => "Bond" })
98
+ # <tt>builder.process({ "id" => 1, "street" => "Bond" })
99
99
  #
100
100
  # Options:
101
101
  #
102
102
  # attrs: The single document attributes to process.
103
103
  def process(attrs)
104
104
  return if reject?(attrs)
105
- if attrs[:_id]
106
- document = existing.find(attrs[:_id])
105
+ if attrs[:id]
106
+ document = existing.find(convert_id(attrs[:id]))
107
107
  destroyable?(attrs) ? document.destroy : document.update_attributes(attrs)
108
108
  else
109
109
  existing.push(metadata.klass.new(attrs)) unless destroyable?(attrs)
@@ -69,7 +69,7 @@ module Mongoid # :nodoc:
69
69
  #
70
70
  # True if the id part of the logic will allow an update.
71
71
  def acceptable_id?
72
- id = attributes[:_id]
72
+ id = convert_id(attributes[:id])
73
73
  existing.id == id || id.nil? || (existing.id != id && update_only?)
74
74
  end
75
75
 
@@ -83,7 +83,7 @@ module Mongoid # :nodoc:
83
83
  #
84
84
  # True if the relation should be deleted.
85
85
  def delete?
86
- destroyable? && !attributes[:_id].nil?
86
+ destroyable? && !attributes[:id].nil?
87
87
  end
88
88
 
89
89
  # Can the existing relation potentially be deleted?
@@ -15,7 +15,7 @@ module Mongoid # :nodoc:
15
15
  #
16
16
  # @return [ Array<Document> ] The documents.
17
17
  def build(type = nil)
18
- return object.dup unless query?
18
+ return object.try(:dup) unless query?
19
19
  begin
20
20
  metadata.klass.find(object)
21
21
  rescue Errors::DocumentNotFound
@@ -13,7 +13,7 @@ module Mongoid # :nodoc:
13
13
  extend ActiveSupport::Concern
14
14
 
15
15
  included do
16
- class_inheritable_accessor :cascades
16
+ class_attribute :cascades
17
17
  self.cascades = []
18
18
  delegate :cascades, :to => "self.class"
19
19
  end
@@ -351,7 +351,7 @@ module Mongoid # :nodoc:
351
351
  #
352
352
  # @return [ Criteria, Object ] A Criteria or return value from the target.
353
353
  def method_missing(name, *args, &block)
354
- load! and return super if target.respond_to?(name)
354
+ load!(:binding => true) and return super if target.respond_to?(name)
355
355
  klass = metadata.klass
356
356
  klass.send(:with_scope, criteria) do
357
357
  klass.send(name, *args)
@@ -9,7 +9,7 @@ module Mongoid # :nodoc:
9
9
 
10
10
  included do
11
11
  cattr_accessor :embedded
12
- class_inheritable_accessor :relations
12
+ class_attribute :relations
13
13
  self.embedded = false
14
14
  self.relations = {}
15
15
 
@@ -119,6 +119,26 @@ module Mongoid #:nodoc:
119
119
  find_or(:build, attrs)
120
120
  end
121
121
 
122
+ # Gets the document as a serializable hash, used by ActiveModel's JSON and
123
+ # XML serializers. This override is just to be able to pass the :include
124
+ # and :except options to get associations in the hash.
125
+ #
126
+ # @example Get the serializable hash.
127
+ # relation.serializable_hash
128
+ #
129
+ # @param [ Hash ] options The options to pass.
130
+ #
131
+ # @option options [ Symbol ] :include What relations to include
132
+ # @option options [ Symbol ] :only Limit the fields to only these.
133
+ # @option options [ Symbol ] :except Dont include these fields.
134
+ #
135
+ # @return [ Hash ] The documents, ready to be serialized.
136
+ #
137
+ # @since 2.0.0.rc.6
138
+ def serializable_hash(options = {})
139
+ target.map { |document| document.serializable_hash(options) }
140
+ end
141
+
122
142
  private
123
143
 
124
144
  # Get the default options used in binding functions.
@@ -425,7 +425,7 @@ module Mongoid # :nodoc:
425
425
  name.to_s << suffix
426
426
  end
427
427
  else
428
- (polymorphic? ? self[:as].to_s : inverse_class_name.underscore) << suffix
428
+ polymorphic? ? "#{self[:as]}#{suffix}" : inverse_class_name.foreign_key
429
429
  end
430
430
  end
431
431
 
@@ -47,6 +47,24 @@ module Mongoid # :nodoc:
47
47
  def update_only?
48
48
  options[:update_only] || false
49
49
  end
50
+
51
+ # Convert an id to its appropriate type.
52
+ #
53
+ # @todo Durran: Move this into a common reusable place.
54
+ #
55
+ # @example Convert the id.
56
+ # builder.convert_id("4d371b444835d98b8b000010")
57
+ #
58
+ # @param [ String ] id The id, usually coming from the form.
59
+ #
60
+ # @return [ BSON::ObjectId, String, Object ] The converted id.
61
+ #
62
+ # @since 2.0.0.rc.6
63
+ def convert_id(id)
64
+ return nil unless id
65
+ model = metadata.klass
66
+ model.using_object_ids? ? BSON::ObjectId.cast!(model, id) : id.class.set(id)
67
+ end
50
68
  end
51
69
  end
52
70
  end
@@ -8,7 +8,7 @@ module Mongoid # :nodoc:
8
8
  extend ActiveSupport::Concern
9
9
 
10
10
  included do
11
- class_inheritable_accessor :polymorphic
11
+ class_attribute :polymorphic
12
12
  delegate :polymorphic?, :to => "self.class"
13
13
  end
14
14
 
@@ -56,6 +56,41 @@ module Mongoid #:nodoc:
56
56
  criteria.count
57
57
  end
58
58
 
59
+ # Creates a new document on the references many relation. This will
60
+ # save the document if the parent has been persisted.
61
+ #
62
+ # @example Create and save the new document.
63
+ # person.posts.create(:text => "Testing")
64
+ #
65
+ # @param [ Hash ] attributes The attributes to create with.
66
+ # @param [ Class ] type The optional type of document to create.
67
+ #
68
+ # @return [ Document ] The newly created document.
69
+ def create(attributes = nil, type = nil)
70
+ build(attributes, type).tap do |doc|
71
+ base.persisted? ? doc.save : raise_unsaved(doc)
72
+ end
73
+ end
74
+
75
+ # Creates a new document on the references many relation. This will
76
+ # save the document if the parent has been persisted and will raise an
77
+ # error if validation fails.
78
+ #
79
+ # @example Create and save the new document.
80
+ # person.posts.create!(:text => "Testing")
81
+ #
82
+ # @param [ Hash ] attributes The attributes to create with.
83
+ # @param [ Class ] type The optional type of document to create.
84
+ #
85
+ # @raise [ Errors::Validations ] If validation failed.
86
+ #
87
+ # @return [ Document ] The newly created document.
88
+ def create!(attributes = nil, type = nil)
89
+ build(attributes, type).tap do |doc|
90
+ base.persisted? ? doc.save! : raise_unsaved(doc)
91
+ end
92
+ end
93
+
59
94
  # Deletes all related documents from the database given the supplied
60
95
  # conditions.
61
96
  #
@@ -233,7 +268,7 @@ module Mongoid #:nodoc:
233
268
  #
234
269
  # @since 2.0.0.rc.1
235
270
  def append(document, options = {})
236
- load! and target.push(document)
271
+ load!(options) and target.push(document)
237
272
  characterize_one(document)
238
273
  binding.bind_one(document, options)
239
274
  end
@@ -274,13 +309,28 @@ module Mongoid #:nodoc:
274
309
  #
275
310
  # @return [ Criteria, Object ] A Criteria or return value from the target.
276
311
  def method_missing(name, *args, &block)
277
- load! and return super if [].respond_to?(name)
312
+ load!(:binding => true) and return super if [].respond_to?(name)
278
313
  klass = metadata.klass
279
314
  klass.send(:with_scope, criteria) do
280
315
  klass.send(name, *args)
281
316
  end
282
317
  end
283
318
 
319
+ # When the base is not yet saved and the user calls create or create!
320
+ # on the relation, this error will get raised.
321
+ #
322
+ # @example Raise the error.
323
+ # relation.raise_unsaved(post)
324
+ #
325
+ # @param [ Document ] doc The child document getting created.
326
+ #
327
+ # @raise [ Errors::UnsavedDocument ] The error.
328
+ #
329
+ # @since 2.0.0.rc.6
330
+ def raise_unsaved(doc)
331
+ raise Errors::UnsavedDocument.new(base, doc)
332
+ end
333
+
284
334
  class << self
285
335
 
286
336
  # Return the builder that is responsible for generating the documents
@@ -7,6 +7,41 @@ module Mongoid # :nodoc:
7
7
  # many-to-many between documents in different collections.
8
8
  class ManyToMany < Referenced::Many
9
9
 
10
+ # Creates a new document on the references many relation. This will
11
+ # save the document if the parent has been persisted.
12
+ #
13
+ # @example Create and save the new document.
14
+ # person.preferences.create(:text => "Testing")
15
+ #
16
+ # @param [ Hash ] attributes The attributes to create with.
17
+ # @param [ Class ] type The optional type of document to create.
18
+ #
19
+ # @return [ Document ] The newly created document.
20
+ def create(attributes = nil, type = nil)
21
+ build(attributes, type).tap do |doc|
22
+ doc.save and base.save if base.persisted?
23
+ end
24
+ end
25
+
26
+ # Creates a new document on the references many relation. This will
27
+ # save the document if the parent has been persisted and will raise an
28
+ # error if validation fails.
29
+ #
30
+ # @example Create and save the new document.
31
+ # person.preferences.create!(:text => "Testing")
32
+ #
33
+ # @param [ Hash ] attributes The attributes to create with.
34
+ # @param [ Class ] type The optional type of document to create.
35
+ #
36
+ # @raise [ Errors::Validations ] If validation failed.
37
+ #
38
+ # @return [ Document ] The newly created document.
39
+ def create!(attributes = nil, type = nil)
40
+ build(attributes, type).tap do |doc|
41
+ doc.save! and base.save! if base.persisted?
42
+ end
43
+ end
44
+
10
45
  # Delete a single document from the relation.
11
46
  #
12
47
  # @example Delete a document.
@@ -199,7 +199,7 @@ module Mongoid #:nodoc:
199
199
  def update_attributes!(attributes = {})
200
200
  target.write_attributes(attributes)
201
201
  update(:safe => safety_options).tap do |result|
202
- target.class.fail_validate!(self) unless result
202
+ target.class.fail_validate!(target) unless result
203
203
  end
204
204
  end
205
205
  end
@@ -0,0 +1,99 @@
1
+ # encoding: utf-8
2
+ module Mongoid # :nodoc:
3
+
4
+ # This module provides the extra behaviour for including relations in JSON
5
+ # and XML serialization.
6
+ module Serialization
7
+ extend ActiveSupport::Concern
8
+ include ActiveModel::Serialization
9
+
10
+ # Gets the document as a serializable hash, used by ActiveModel's JSON and
11
+ # XML serializers. This override is just to be able to pass the :include
12
+ # and :except options to get associations in the hash.
13
+ #
14
+ # @example Get the serializable hash.
15
+ # document.serializable_hash
16
+ #
17
+ # @example Get the serializable hash with options.
18
+ # document.serializable_hash(:include => :addresses)
19
+ #
20
+ # @param [ Hash ] options The options to pass.
21
+ #
22
+ # @option options [ Symbol ] :include What relations to include
23
+ # @option options [ Symbol ] :only Limit the fields to only these.
24
+ # @option options [ Symbol ] :except Dont include these fields.
25
+ #
26
+ # @return [ Hash ] The document, ready to be serialized.
27
+ #
28
+ # @since 2.0.0.rc.6
29
+ def serializable_hash(options = nil)
30
+ options ||= {}
31
+ super(options).tap do |attrs|
32
+ serialize_relations(attrs, options) if options[:include]
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ # For each of the provided include options, get the relation needed and
39
+ # provide it in the hash.
40
+ #
41
+ # @example Serialize the included relations.
42
+ # document.serialize_relations({}, :include => :addresses)
43
+ #
44
+ # @param [ Hash ] attributes The attributes to serialize.
45
+ # @param [ Hash ] options The serialization options.
46
+ #
47
+ # @option options [ Symbol ] :include What relations to include
48
+ # @option options [ Symbol ] :only Limit the fields to only these.
49
+ # @option options [ Symbol ] :except Dont include these fields.
50
+ #
51
+ # @since 2.0.0.rc.6
52
+ def serialize_relations(attributes = {}, options = {})
53
+ inclusions = options.delete(:include)
54
+ relation_names(inclusions).each do |name|
55
+ metadata = relations[name.to_s]
56
+ relation = send(metadata.name, false, :eager => true)
57
+ if relation
58
+ attributes[metadata.name.to_s] =
59
+ relation.serializable_hash(relation_options(inclusions, options, name))
60
+ end
61
+ end
62
+ end
63
+
64
+ # Since the inclusions can be a hash, symbol, or array of symbols, this is
65
+ # provided as a convenience to parse out the names.
66
+ #
67
+ # @example Get the relation names.
68
+ # document.relation_names(:include => [ :addresses ])
69
+ #
70
+ # @param [ Hash, Symbol, Array<Symbol ] inclusions The inclusions.
71
+ #
72
+ # @return [ Array<Symbol> ] The names of the included relations.
73
+ #
74
+ # @since 2.0.0.rc.6
75
+ def relation_names(inclusions)
76
+ inclusions.is_a?(Hash) ? inclusions.keys : Array.wrap(inclusions)
77
+ end
78
+
79
+ # Since the inclusions can be a hash, symbol, or array of symbols, this is
80
+ # provided as a convenience to parse out the options.
81
+ #
82
+ # @example Get the relation options.
83
+ # document.relation_names(:include => [ :addresses ])
84
+ #
85
+ # @param [ Hash, Symbol, Array<Symbol ] inclusions The inclusions.
86
+ # @param [ Symbol ] name The name of the relation.
87
+ #
88
+ # @return [ Hash ] The options for the relation.
89
+ #
90
+ # @since 2.0.0.rc.6
91
+ def relation_options(inclusions, options, name)
92
+ if inclusions.is_a?(Hash)
93
+ inclusions[name]
94
+ else
95
+ { :except => options[:except], :only => options[:only] }
96
+ end
97
+ end
98
+ end
99
+ end
@@ -13,7 +13,7 @@ module Mongoid #:nodoc:
13
13
  set_callback :create, :before, :set_created_at
14
14
  set_callback :save, :before, :set_updated_at
15
15
 
16
- class_inheritable_accessor :record_timestamps, :instance_writer => false
16
+ class_attribute :record_timestamps
17
17
  self.record_timestamps = true
18
18
  end
19
19
 
@@ -8,46 +8,57 @@ module Mongoid #:nodoc:
8
8
  # provide: validates_associated and validates_uniqueness_of.
9
9
  module Validations
10
10
  extend ActiveSupport::Concern
11
+ include ActiveModel::Validations
11
12
 
12
- included do
13
- include ActiveModel::Validations
13
+ attr_accessor :validated
14
14
 
15
- attr_accessor :validated
16
-
17
- # Overrides the default ActiveModel behaviour since we need to handle
18
- # validations of relations slightly different than just calling the
19
- # getter.
20
- #
21
- # @todo Durran: Why does moving the ActiveModel::Validations include
22
- # statement outside of the block bomb the test suite. This feels dirty.
23
- #
24
- # @example Read the value.
25
- # person.read_attribute_for_validation(:addresses)
26
- #
27
- # @param [ Symbol ] attr The name of the field or relation.
28
- #
29
- # @return [ Object ] The value of the field or the relation.
30
- #
31
- # @since 2.0.0.rc.1
32
- def read_attribute_for_validation(attr)
33
- if relations[attr.to_s]
34
- send(attr, false, :continue => false, :eager => true)
35
- else
36
- send(attr)
37
- end
15
+ # Overrides the default ActiveModel behaviour since we need to handle
16
+ # validations of relations slightly different than just calling the
17
+ # getter.
18
+ #
19
+ # @example Read the value.
20
+ # person.read_attribute_for_validation(:addresses)
21
+ #
22
+ # @param [ Symbol ] attr The name of the field or relation.
23
+ #
24
+ # @return [ Object ] The value of the field or the relation.
25
+ #
26
+ # @since 2.0.0.rc.1
27
+ def read_attribute_for_validation(attr)
28
+ if relations[attr.to_s]
29
+ send(attr, false, :eager => true)
30
+ else
31
+ send(attr)
38
32
  end
33
+ end
39
34
 
40
- # Used to prevent infinite loops in associated validations.
41
- #
42
- # @example Is the document validated?
43
- # document.validated?
44
- #
45
- # @return [ true, false ] Has the document already been validated?
46
- #
47
- # @since 2.0.0.rc.2
48
- def validated?
49
- !!@validated
50
- end
35
+ # Determine if the document is valid.
36
+ #
37
+ # @example Is the document valid?
38
+ # person.valid?
39
+ #
40
+ # @example Is the document valid in a context?
41
+ # person.valid?(:create)
42
+ #
43
+ # @param [ Symbol ] context The optional validation context.
44
+ #
45
+ # @return [ true, false ] True if valid, false if not.
46
+ #
47
+ # @since 2.0.0.rc.6
48
+ def valid?(context = nil)
49
+ super context ? context : (new? ? :create : :update)
50
+ end
51
+
52
+ # Used to prevent infinite loops in associated validations.
53
+ #
54
+ # @example Is the document validated?
55
+ # document.validated?
56
+ #
57
+ # @return [ true, false ] Has the document already been validated?
58
+ #
59
+ # @since 2.0.0.rc.2
60
+ def validated?
61
+ !!@validated
51
62
  end
52
63
 
53
64
  module ClassMethods #:nodoc:
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Mongoid #:nodoc
3
- VERSION = "2.0.0.rc.5"
3
+ VERSION = "2.0.0.rc.6"
4
4
  end
metadata CHANGED
@@ -7,8 +7,8 @@ version: !ruby/object:Gem::Version
7
7
  - 0
8
8
  - 0
9
9
  - rc
10
- - 5
11
- version: 2.0.0.rc.5
10
+ - 6
11
+ version: 2.0.0.rc.6
12
12
  platform: ruby
13
13
  authors:
14
14
  - Durran Jordan
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2011-01-16 00:00:00 +01:00
19
+ date: 2011-01-19 00:00:00 +01:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
@@ -72,9 +72,8 @@ dependencies:
72
72
  - !ruby/object:Gem::Version
73
73
  segments:
74
74
  - 1
75
- - 1
76
- - 5
77
- version: 1.1.5
75
+ - 2
76
+ version: "1.2"
78
77
  type: :runtime
79
78
  prerelease: false
80
79
  version_requirements: *id004
@@ -87,9 +86,8 @@ dependencies:
87
86
  - !ruby/object:Gem::Version
88
87
  segments:
89
88
  - 1
90
- - 1
91
- - 5
92
- version: 1.1.5
89
+ - 2
90
+ version: "1.2"
93
91
  type: :development
94
92
  prerelease: false
95
93
  version_requirements: *id005
@@ -201,6 +199,7 @@ files:
201
199
  - lib/mongoid/errors/invalid_type.rb
202
200
  - lib/mongoid/errors/mongoid_error.rb
203
201
  - lib/mongoid/errors/too_many_nested_attribute_records.rb
202
+ - lib/mongoid/errors/unsaved_document.rb
204
203
  - lib/mongoid/errors/unsupported_version.rb
205
204
  - lib/mongoid/errors/validations.rb
206
205
  - lib/mongoid/errors.rb
@@ -324,6 +323,7 @@ files:
324
323
  - lib/mongoid/safe.rb
325
324
  - lib/mongoid/safety.rb
326
325
  - lib/mongoid/scope.rb
326
+ - lib/mongoid/serialization.rb
327
327
  - lib/mongoid/state.rb
328
328
  - lib/mongoid/timestamps.rb
329
329
  - lib/mongoid/validations/associated.rb
@@ -338,7 +338,7 @@ files:
338
338
  - lib/rails/generators/mongoid/model/templates/model.rb
339
339
  - lib/rails/generators/mongoid_generator.rb
340
340
  - lib/rails/mongoid.rb
341
- - MIT_LICENSE
341
+ - LICENSE
342
342
  - README.rdoc
343
343
  - Rakefile
344
344
  has_rdoc: true
@@ -355,7 +355,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
355
355
  requirements:
356
356
  - - ">="
357
357
  - !ruby/object:Gem::Version
358
- hash: -3904513981579822953
358
+ hash: 1229276417221731393
359
359
  segments:
360
360
  - 0
361
361
  version: "0"