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

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 (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