mongoid 2.0.0.beta.20 → 2.0.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. data/README.rdoc +8 -0
  2. data/Rakefile +51 -0
  3. data/lib/config/locales/nl.yml +39 -0
  4. data/lib/config/locales/ro.yml +1 -1
  5. data/lib/mongoid.rb +17 -17
  6. data/lib/mongoid/atomicity.rb +54 -22
  7. data/lib/mongoid/attributes.rb +145 -125
  8. data/lib/mongoid/callbacks.rb +7 -2
  9. data/lib/mongoid/collection.rb +49 -32
  10. data/lib/mongoid/collections.rb +0 -1
  11. data/lib/mongoid/components.rb +34 -29
  12. data/lib/mongoid/config.rb +207 -193
  13. data/lib/mongoid/config/database.rb +167 -0
  14. data/lib/mongoid/contexts.rb +2 -5
  15. data/lib/mongoid/contexts/enumerable.rb +30 -4
  16. data/lib/mongoid/contexts/ids.rb +2 -2
  17. data/lib/mongoid/contexts/mongo.rb +30 -5
  18. data/lib/mongoid/copyable.rb +44 -0
  19. data/lib/mongoid/criteria.rb +110 -56
  20. data/lib/mongoid/criterion/creational.rb +34 -0
  21. data/lib/mongoid/criterion/destructive.rb +37 -0
  22. data/lib/mongoid/criterion/exclusion.rb +3 -1
  23. data/lib/mongoid/criterion/inclusion.rb +59 -64
  24. data/lib/mongoid/criterion/inspection.rb +22 -0
  25. data/lib/mongoid/criterion/optional.rb +42 -54
  26. data/lib/mongoid/criterion/selector.rb +9 -0
  27. data/lib/mongoid/default_scope.rb +28 -0
  28. data/lib/mongoid/deprecation.rb +5 -5
  29. data/lib/mongoid/dirty.rb +4 -5
  30. data/lib/mongoid/document.rb +161 -114
  31. data/lib/mongoid/extensions.rb +7 -11
  32. data/lib/mongoid/extensions/array/parentization.rb +2 -2
  33. data/lib/mongoid/extensions/date/conversions.rb +1 -1
  34. data/lib/mongoid/extensions/hash/conversions.rb +0 -23
  35. data/lib/mongoid/extensions/nil/collectionization.rb +12 -0
  36. data/lib/mongoid/extensions/object/reflections.rb +17 -0
  37. data/lib/mongoid/extensions/object/yoda.rb +27 -0
  38. data/lib/mongoid/extensions/string/conversions.rb +23 -4
  39. data/lib/mongoid/extensions/time_conversions.rb +4 -4
  40. data/lib/mongoid/field.rb +30 -19
  41. data/lib/mongoid/fields.rb +15 -5
  42. data/lib/mongoid/finders.rb +19 -11
  43. data/lib/mongoid/hierarchy.rb +34 -28
  44. data/lib/mongoid/identity.rb +62 -20
  45. data/lib/mongoid/inspection.rb +58 -0
  46. data/lib/mongoid/matchers.rb +20 -0
  47. data/lib/mongoid/multi_database.rb +11 -0
  48. data/lib/mongoid/nested_attributes.rb +41 -0
  49. data/lib/mongoid/paranoia.rb +3 -4
  50. data/lib/mongoid/paths.rb +1 -1
  51. data/lib/mongoid/persistence.rb +89 -90
  52. data/lib/mongoid/persistence/command.rb +20 -4
  53. data/lib/mongoid/persistence/insert.rb +13 -11
  54. data/lib/mongoid/persistence/insert_embedded.rb +8 -6
  55. data/lib/mongoid/persistence/remove.rb +6 -4
  56. data/lib/mongoid/persistence/remove_all.rb +6 -4
  57. data/lib/mongoid/persistence/remove_embedded.rb +8 -6
  58. data/lib/mongoid/persistence/update.rb +12 -10
  59. data/lib/mongoid/railtie.rb +2 -2
  60. data/lib/mongoid/railties/database.rake +10 -9
  61. data/lib/mongoid/relations.rb +104 -0
  62. data/lib/mongoid/relations/accessors.rb +154 -0
  63. data/lib/mongoid/relations/auto_save.rb +34 -0
  64. data/lib/mongoid/relations/binding.rb +24 -0
  65. data/lib/mongoid/relations/bindings.rb +9 -0
  66. data/lib/mongoid/relations/bindings/embedded/in.rb +77 -0
  67. data/lib/mongoid/relations/bindings/embedded/many.rb +93 -0
  68. data/lib/mongoid/relations/bindings/embedded/one.rb +65 -0
  69. data/lib/mongoid/relations/bindings/referenced/in.rb +78 -0
  70. data/lib/mongoid/relations/bindings/referenced/many.rb +93 -0
  71. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +94 -0
  72. data/lib/mongoid/relations/bindings/referenced/one.rb +63 -0
  73. data/lib/mongoid/relations/builder.rb +41 -0
  74. data/lib/mongoid/relations/builders.rb +79 -0
  75. data/lib/mongoid/relations/builders/embedded/in.rb +25 -0
  76. data/lib/mongoid/relations/builders/embedded/many.rb +32 -0
  77. data/lib/mongoid/relations/builders/embedded/one.rb +26 -0
  78. data/lib/mongoid/relations/builders/nested_attributes/many.rb +116 -0
  79. data/lib/mongoid/relations/builders/nested_attributes/one.rb +135 -0
  80. data/lib/mongoid/relations/builders/referenced/in.rb +32 -0
  81. data/lib/mongoid/relations/builders/referenced/many.rb +26 -0
  82. data/lib/mongoid/relations/builders/referenced/many_to_many.rb +29 -0
  83. data/lib/mongoid/relations/builders/referenced/one.rb +30 -0
  84. data/lib/mongoid/relations/cascading.rb +55 -0
  85. data/lib/mongoid/relations/cascading/delete.rb +19 -0
  86. data/lib/mongoid/relations/cascading/destroy.rb +19 -0
  87. data/lib/mongoid/relations/cascading/nullify.rb +18 -0
  88. data/lib/mongoid/relations/cascading/strategy.rb +26 -0
  89. data/lib/mongoid/relations/cyclic.rb +97 -0
  90. data/lib/mongoid/relations/embedded/in.rb +172 -0
  91. data/lib/mongoid/relations/embedded/many.rb +450 -0
  92. data/lib/mongoid/relations/embedded/one.rb +169 -0
  93. data/lib/mongoid/relations/macros.rb +302 -0
  94. data/lib/mongoid/relations/many.rb +185 -0
  95. data/lib/mongoid/relations/metadata.rb +529 -0
  96. data/lib/mongoid/relations/nested_builder.rb +52 -0
  97. data/lib/mongoid/relations/one.rb +29 -0
  98. data/lib/mongoid/relations/polymorphic.rb +54 -0
  99. data/lib/mongoid/relations/proxy.rb +122 -0
  100. data/lib/mongoid/relations/referenced/in.rb +214 -0
  101. data/lib/mongoid/relations/referenced/many.rb +358 -0
  102. data/lib/mongoid/relations/referenced/many_to_many.rb +379 -0
  103. data/lib/mongoid/relations/referenced/one.rb +204 -0
  104. data/lib/mongoid/relations/reflections.rb +45 -0
  105. data/lib/mongoid/safe.rb +11 -1
  106. data/lib/mongoid/safety.rb +122 -97
  107. data/lib/mongoid/scope.rb +14 -9
  108. data/lib/mongoid/state.rb +37 -3
  109. data/lib/mongoid/timestamps.rb +11 -0
  110. data/lib/mongoid/validations.rb +42 -3
  111. data/lib/mongoid/validations/associated.rb +8 -5
  112. data/lib/mongoid/validations/uniqueness.rb +23 -2
  113. data/lib/mongoid/version.rb +1 -1
  114. data/lib/mongoid/versioning.rb +25 -16
  115. data/lib/rails/generators/mongoid/model/templates/model.rb +3 -1
  116. metadata +95 -80
  117. data/lib/mongoid/associations.rb +0 -364
  118. data/lib/mongoid/associations/embedded_in.rb +0 -74
  119. data/lib/mongoid/associations/embeds_many.rb +0 -299
  120. data/lib/mongoid/associations/embeds_one.rb +0 -111
  121. data/lib/mongoid/associations/foreign_key.rb +0 -35
  122. data/lib/mongoid/associations/meta_data.rb +0 -38
  123. data/lib/mongoid/associations/options.rb +0 -78
  124. data/lib/mongoid/associations/proxy.rb +0 -60
  125. data/lib/mongoid/associations/referenced_in.rb +0 -70
  126. data/lib/mongoid/associations/references_many.rb +0 -254
  127. data/lib/mongoid/associations/references_many_as_array.rb +0 -128
  128. data/lib/mongoid/associations/references_one.rb +0 -104
  129. data/lib/mongoid/extensions/array/accessors.rb +0 -17
  130. data/lib/mongoid/extensions/array/assimilation.rb +0 -26
  131. data/lib/mongoid/extensions/hash/accessors.rb +0 -42
  132. data/lib/mongoid/extensions/hash/assimilation.rb +0 -40
  133. data/lib/mongoid/extensions/nil/assimilation.rb +0 -17
  134. data/lib/mongoid/memoization.rb +0 -33
@@ -0,0 +1,78 @@
1
+ # encoding: utf-8
2
+ module Mongoid # :nodoc:
3
+ module Relations #:nodoc:
4
+ module Bindings #:nodoc:
5
+ module Referenced #:nodoc:
6
+
7
+ # Binding class for all referenced_in relations.
8
+ class In < Binding
9
+
10
+ # Binds the base object to the inverse of the relation. This is so we
11
+ # are referenced to the actual objects themselves on both sides.
12
+ #
13
+ # This case sets the metadata on the inverse object as well as the
14
+ # document itself.
15
+ #
16
+ # @example Bind the documents.
17
+ # game.person.bind(:continue => true)
18
+ # game.person = Person.new
19
+ #
20
+ # @param [ Hash ] options The binding options.
21
+ #
22
+ # @option options [ true, false ] :continue Continue binding the inverse.
23
+ # @option options [ true, false ] :building Are we in build mode?
24
+ #
25
+ # @since 2.0.0.rc.1
26
+ def bind(options = {})
27
+ inverse = metadata.inverse(target)
28
+ base.send(metadata.foreign_key_setter, target.id)
29
+ if metadata.inverse_type
30
+ base.send(metadata.inverse_type_setter, target.class.name)
31
+ end
32
+ if inverse
33
+ base.metadata = target.reflect_on_association(inverse)
34
+ if options[:continue]
35
+ if base.referenced_many?
36
+ target.do_or_do_not(
37
+ inverse,
38
+ false,
39
+ :building => true,
40
+ :continue => false
41
+ ).push(base, :building => true, :continue => false)
42
+ else
43
+ target.do_or_do_not(
44
+ metadata.inverse_setter(target),
45
+ base,
46
+ :building => true,
47
+ :continue => false
48
+ )
49
+ end
50
+ end
51
+ end
52
+ end
53
+ alias :bind_one :bind
54
+
55
+ # Unbinds the base object and the inverse, caused by setting the
56
+ # reference to nil.
57
+ #
58
+ # @example Unbind the document.
59
+ # game.person.unbind(:continue => true)
60
+ # game.person = nil
61
+ #
62
+ # @param [ Hash ] options The options to pass through.
63
+ #
64
+ # @option options [ true, false ] :continue Do we continue unbinding?
65
+ #
66
+ # @since 2.0.0.rc.1
67
+ def unbind(options = {})
68
+ base.do_or_do_not(metadata.foreign_key_setter, nil)
69
+ if options[:continue]
70
+ target.do_or_do_not(metadata.inverse_setter(target), nil, :continue => false)
71
+ end
72
+ end
73
+ alias :unbind_one :unbind
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,93 @@
1
+ # encoding: utf-8
2
+ module Mongoid # :nodoc:
3
+ module Relations #:nodoc:
4
+ module Bindings #:nodoc:
5
+ module Referenced #:nodoc:
6
+
7
+ # Binding class for references_many relations.
8
+ class Many < Binding
9
+
10
+ # Binds the base object to the inverse of the relation. This is so we
11
+ # are referenced to the actual objects themselves on both sides.
12
+ #
13
+ # This case sets the metadata on the inverse object as well as the
14
+ # document itself.
15
+ #
16
+ # @example Bind all the documents.
17
+ # person.posts.bind
18
+ # person.posts = [ Post.new ]
19
+ #
20
+ # @param [ Hash ] options The binding options.
21
+ #
22
+ # @option options [ true, false ] :continue Continue binding the inverse.
23
+ # @option options [ true, false ] :building Are we in build mode?
24
+ #
25
+ # @since 2.0.0.rc.1
26
+ def bind(options = {})
27
+ target.each { |doc| bind_one(doc, options) }
28
+ end
29
+
30
+ # Binds a single document with the inverse relation. Used
31
+ # specifically when appending to the proxy.
32
+ #
33
+ # @example Bind one document.
34
+ # person.posts.bind_one(post)
35
+ #
36
+ # @param [ Document ] doc The single document to bind.
37
+ # @param [ Hash ] options The binding options.
38
+ #
39
+ # @option options [ true, false ] :continue Continue binding the inverse.
40
+ # @option options [ true, false ] :building Are we in build mode?
41
+ #
42
+ # @since 2.0.0.rc.1
43
+ def bind_one(doc, options = {})
44
+ if options[:continue]
45
+ doc.do_or_do_not(metadata.foreign_key_setter, base.id)
46
+ doc.do_or_do_not(
47
+ metadata.inverse_setter,
48
+ base,
49
+ :building => true,
50
+ :continue => false
51
+ )
52
+ end
53
+ end
54
+
55
+ # Unbinds the base object and the inverse, caused by setting the
56
+ # reference to nil.
57
+ #
58
+ # @example Unbind the documents.
59
+ # person.posts.unbind
60
+ # person.posts = nil
61
+ #
62
+ # @param [ Hash ] options The binding options.
63
+ #
64
+ # @option options [ true, false ] :continue Continue binding the inverse.
65
+ # @option options [ true, false ] :building Are we in build mode?
66
+ #
67
+ # @since 2.0.0.rc.1
68
+ def unbind(options = {})
69
+ target.each { |doc| unbind_one(doc, options) }
70
+ end
71
+
72
+ # Unbind a single document.
73
+ #
74
+ # @example Unbind the document.
75
+ # person.posts.unbind_one(document)
76
+ #
77
+ # @param [ Hash ] options The binding options.
78
+ #
79
+ # @option options [ true, false ] :continue Continue binding the inverse.
80
+ # @option options [ true, false ] :building Are we in build mode?
81
+ #
82
+ # @since 2.0.0.rc.1
83
+ def unbind_one(doc, options = {})
84
+ if options[:continue]
85
+ doc.do_or_do_not(metadata.foreign_key_setter, nil)
86
+ doc.do_or_do_not(metadata.inverse_setter, nil, :continue => false)
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,94 @@
1
+ # encoding: utf-8
2
+ module Mongoid # :nodoc:
3
+ module Relations #:nodoc:
4
+ module Bindings #:nodoc:
5
+ module Referenced #:nodoc:
6
+
7
+ # Binding class for all references_and_referenced_in_many relations.
8
+ class ManyToMany < Binding
9
+
10
+ # Binds the base object to the inverse of the relation. This is so we
11
+ # are referenced to the actual objects themselves on both sides.
12
+ #
13
+ # This case sets the metadata on the inverse object as well as the
14
+ # document itself.
15
+ #
16
+ # @example Bind all the documents.
17
+ # person.preferences.bind
18
+ # person.preferences = [ Preference.new ]
19
+ #
20
+ # @param [ Hash ] options The binding options.
21
+ #
22
+ # @option options [ true, false ] :continue Continue binding the inverse.
23
+ # @option options [ true, false ] :building Are we in build mode?
24
+ #
25
+ # @since 2.0.0.rc.1
26
+ def bind(options = {})
27
+ target.each { |doc| bind_one(doc, options) }
28
+ end
29
+
30
+ # Binds a single document with the inverse relation. Used
31
+ # specifically when appending to the proxy.
32
+ #
33
+ # @example Bind one document.
34
+ # person.preferences.bind_one(preference)
35
+ #
36
+ # @param [ Document ] doc The single document to bind.
37
+ # @param [ Hash ] options The binding options.
38
+ #
39
+ # @option options [ true, false ] :continue Continue binding the inverse.
40
+ # @option options [ true, false ] :building Are we in build mode?
41
+ #
42
+ # @since 2.0.0.rc.1
43
+ def bind_one(doc, options = {})
44
+ keys = base.do_or_do_not(metadata.foreign_key)
45
+ keys.push(doc.id) unless keys.include?(doc.id)
46
+ if options[:continue]
47
+ doc.do_or_do_not(
48
+ metadata.inverse(target),
49
+ false,
50
+ :building => true,
51
+ :continue => false
52
+ ).push(base, :continue => false)
53
+ end
54
+ end
55
+
56
+ # Unbinds the base object and the inverse, caused by setting the
57
+ # reference to nil.
58
+ #
59
+ # @example Unbind the documents.
60
+ # person.preferences.unbind
61
+ # person.preferences = nil
62
+ #
63
+ # @param [ Hash ] options The binding options.
64
+ #
65
+ # @option options [ true, false ] :continue Continue binding the inverse.
66
+ # @option options [ true, false ] :building Are we in build mode?
67
+ #
68
+ # @since 2.0.0.rc.1
69
+ def unbind(options = {})
70
+ target.each { |doc| unbind_one(doc, options) }
71
+ end
72
+
73
+ # Unbind a single document.
74
+ #
75
+ # @example Unbind the document.
76
+ # person.preferences.unbind_one(document)
77
+ #
78
+ # @param [ Hash ] options The binding options.
79
+ #
80
+ # @option options [ true, false ] :continue Continue binding the inverse.
81
+ # @option options [ true, false ] :building Are we in build mode?
82
+ #
83
+ # @since 2.0.0.rc.1
84
+ def unbind_one(doc, options = {})
85
+ base.do_or_do_not(metadata.foreign_key).delete(doc.id)
86
+ if options[:continue]
87
+ doc.do_or_do_not(metadata.inverse(target)).delete(base)
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,63 @@
1
+ # encoding: utf-8
2
+ module Mongoid # :nodoc:
3
+ module Relations #:nodoc:
4
+ module Bindings #:nodoc:
5
+ module Referenced #:nodoc:
6
+
7
+ # Binding class for references_one relations.
8
+ class One < Binding
9
+
10
+ # Binds the base object to the inverse of the relation. This is so we
11
+ # are referenced to the actual objects themselves on both sides.
12
+ #
13
+ # This case sets the metadata on the inverse object as well as the
14
+ # document itself.
15
+ #
16
+ # @example Bind the document.
17
+ # person.game.bind(:continue => true)
18
+ # person.game = Game.new
19
+ #
20
+ # @param [ Hash ] options The options to pass through.
21
+ #
22
+ # @option options [ true, false ] :continue Do we continue binding?
23
+ # @option options [ true, false ] :building Are we in build mode?
24
+ #
25
+ # @since 2.0.0.rc.1
26
+ def bind(options = {})
27
+ if options[:continue]
28
+ target.do_or_do_not(metadata.foreign_key_setter, base.id)
29
+ target.do_or_do_not(
30
+ metadata.inverse_setter,
31
+ base,
32
+ :building => true,
33
+ :continue => false
34
+ )
35
+ end
36
+ end
37
+ alias :bind_one :bind
38
+
39
+ # Unbinds the base object and the inverse, caused by setting the
40
+ # reference to nil.
41
+ #
42
+ # @example Unbind the document.
43
+ # person.game.unbind(:continue => true)
44
+ # person.game = nil
45
+ #
46
+ # @param [ Hash ] options The options to pass through.
47
+ #
48
+ # @option options [ true, false ] :continue Do we continue unbinding?
49
+ # @option options [ true, false ] :building Are we in build mode?
50
+ #
51
+ # @since 2.0.0.rc.1
52
+ def unbind(options = {})
53
+ if options[:continue]
54
+ target.do_or_do_not(metadata.foreign_key_setter, nil)
55
+ target.do_or_do_not(metadata.inverse_setter, nil, :continue => false)
56
+ end
57
+ end
58
+ alias :unbind_one :unbind
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+ module Mongoid # :nodoc:
3
+ module Relations #:nodoc:
4
+
5
+ # Superclass for all builder objects. Builders are responsible for either
6
+ # looking up a relation's target from the database, or creating them from a
7
+ # supplied attributes hash.
8
+ class Builder
9
+
10
+ attr_reader :metadata, :object
11
+ # Instantiate the new builder for a relation.
12
+ #
13
+ # @example Create the builder.
14
+ # Builder.new(metadata, { :field => "value })
15
+ #
16
+ # @param [ Metdata ] metadata The metadata for the relation.
17
+ # @param [ Hash, BSON::ObjectId ] object The attributes to build from or
18
+ # id to query with.
19
+ #
20
+ # @since 2.0.0.rc.1
21
+ def initialize(metadata, object)
22
+ @metadata, @object = metadata, object
23
+ end
24
+
25
+ protected
26
+ # Do we need to perform a database query? It will be so if the object we
27
+ # have is not a document.
28
+ #
29
+ # @example Should we query the database?
30
+ # builder.query?
31
+ #
32
+ # @return [ true, false ] Whether a database query should happen.
33
+ #
34
+ # @since 2.0.0.rc.1
35
+ def query?
36
+ obj = object.to_a.first
37
+ !obj.respond_to?(:attributes) && !obj.nil?
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,79 @@
1
+ # encoding: utf-8
2
+ require "mongoid/relations/builder"
3
+ require "mongoid/relations/nested_builder"
4
+ require "mongoid/relations/builders/embedded/in"
5
+ require "mongoid/relations/builders/embedded/many"
6
+ require "mongoid/relations/builders/embedded/one"
7
+ require "mongoid/relations/builders/nested_attributes/one"
8
+ require "mongoid/relations/builders/nested_attributes/many"
9
+ require "mongoid/relations/builders/referenced/in"
10
+ require "mongoid/relations/builders/referenced/many"
11
+ require "mongoid/relations/builders/referenced/many_to_many"
12
+ require "mongoid/relations/builders/referenced/one"
13
+
14
+ module Mongoid # :nodoc:
15
+ module Relations #:nodoc:
16
+
17
+ # This module is responsible for defining the build and create methods used
18
+ # in one to one relations.
19
+ #
20
+ # @example Methods that get created.
21
+ #
22
+ # class Person
23
+ # include Mongoid::Document
24
+ # embeds_one :name
25
+ # end
26
+ #
27
+ # # The following methods get created:
28
+ # person.build_name({ :first_name => "Durran" })
29
+ # person.create_name({ :first_name => "Durran" })
30
+ #
31
+ # @since 2.0.0.rc.1
32
+ module Builders
33
+ extend ActiveSupport::Concern
34
+
35
+ module ClassMethods #:nodoc:
36
+
37
+ # Defines a builder method for an embeds_one relation. This is
38
+ # defined as #build_name.
39
+ #
40
+ # @example
41
+ # Person.builder("name")
42
+ #
43
+ # @param [ String, Symbol ] name The name of the relation.
44
+ #
45
+ # @return [ Class ] The class being set up.
46
+ #
47
+ # @since 2.0.0.rc.1
48
+ def builder(name)
49
+ tap do
50
+ define_method("build_#{name}") do |*args|
51
+ attributes = (args.any? ? args : []) + [{:building => true}]
52
+ send("#{name}=", *attributes)
53
+ end
54
+ end
55
+ end
56
+
57
+ # Defines a creator method for an embeds_one relation. This is
58
+ # defined as #create_name. After the object is built it will
59
+ # immediately save.
60
+ #
61
+ # @example
62
+ # Person.creator("name")
63
+ #
64
+ # @param [ String, Symbol ] name The name of the relation.
65
+ #
66
+ # @return [ Class ] The class being set up.
67
+ #
68
+ # @since 2.0.0.rc.1
69
+ def creator(name)
70
+ tap do
71
+ define_method("create_#{name}") do |*args|
72
+ send("build_#{name}", *args).tap(&:save)
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end