mongoid 2.0.0.rc.5 → 2.0.0.rc.6

Sign up to get free protection for your applications and to get access to all the features.
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"