clone 1.0.0.alpha → 1.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (189) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/Gemfile +1 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +22 -1
  6. data/VERSION +1 -1
  7. data/bin/clone +7 -0
  8. data/clone.gemspec +4 -0
  9. data/docs/readme +16 -0
  10. data/docs/readme.txt +5 -0
  11. data/lib/clone.rb +13 -2
  12. data/lib/clone/config/config.rb +19 -0
  13. data/lib/clone/config/config.yml +22 -0
  14. data/lib/clone/config/default_config.yml +20 -0
  15. data/lib/clone/config/require.rb +3 -0
  16. data/lib/clone/config/version.rb +10 -0
  17. data/lib/clone/config/yml.rb +22 -0
  18. data/lib/clone/config/z_defaults.rb +28 -0
  19. data/lib/clone/generator/engine.rb +581 -0
  20. data/lib/clone/generator/terminal.rb +104 -0
  21. data/lib/clone/helpers/helper_methods.rb +251 -0
  22. data/lib/clone/helpers/local_methods.rb +150 -0
  23. data/lib/clone/helpers/require.rb +37 -0
  24. data/module/Marshal.4.8 +0 -0
  25. data/module/Marshal.4.8.Z +0 -0
  26. data/module/gems/commander-4.1.3/.gitignore +6 -0
  27. data/module/gems/commander-4.1.3/.travis.yml +11 -0
  28. data/module/gems/commander-4.1.3/DEVELOPMENT +15 -0
  29. data/module/gems/commander-4.1.3/Gemfile +3 -0
  30. data/module/gems/commander-4.1.3/History.rdoc +345 -0
  31. data/module/gems/commander-4.1.3/Manifest +38 -0
  32. data/module/gems/commander-4.1.3/README.rdoc +375 -0
  33. data/module/gems/commander-4.1.3/Rakefile +10 -0
  34. data/module/gems/commander-4.1.3/bin/commander +55 -0
  35. data/module/gems/commander-4.1.3/commander.gemspec +26 -0
  36. data/module/gems/commander-4.1.3/lib/commander.rb +32 -0
  37. data/module/gems/commander-4.1.3/lib/commander/blank.rb +8 -0
  38. data/module/gems/commander-4.1.3/lib/commander/command.rb +213 -0
  39. data/module/gems/commander-4.1.3/lib/commander/core_ext.rb +3 -0
  40. data/module/gems/commander-4.1.3/lib/commander/core_ext/array.rb +26 -0
  41. data/module/gems/commander-4.1.3/lib/commander/core_ext/object.rb +11 -0
  42. data/module/gems/commander-4.1.3/lib/commander/delegates.rb +13 -0
  43. data/module/gems/commander-4.1.3/lib/commander/help_formatters.rb +8 -0
  44. data/module/gems/commander-4.1.3/lib/commander/help_formatters/base.rb +18 -0
  45. data/module/gems/commander-4.1.3/lib/commander/help_formatters/terminal.rb +20 -0
  46. data/module/gems/commander-4.1.3/lib/commander/help_formatters/terminal/command_help.erb +35 -0
  47. data/module/gems/commander-4.1.3/lib/commander/help_formatters/terminal/help.erb +36 -0
  48. data/module/gems/commander-4.1.3/lib/commander/help_formatters/terminal_compact.rb +12 -0
  49. data/module/gems/commander-4.1.3/lib/commander/help_formatters/terminal_compact/command_help.erb +27 -0
  50. data/module/gems/commander-4.1.3/lib/commander/help_formatters/terminal_compact/help.erb +29 -0
  51. data/module/gems/commander-4.1.3/lib/commander/import.rb +10 -0
  52. data/module/gems/commander-4.1.3/lib/commander/platform.rb +8 -0
  53. data/module/gems/commander-4.1.3/lib/commander/runner.rb +411 -0
  54. data/module/gems/commander-4.1.3/lib/commander/user_interaction.rb +521 -0
  55. data/module/gems/commander-4.1.3/lib/commander/version.rb +3 -0
  56. data/module/gems/commander-4.1.3/spec/command_spec.rb +157 -0
  57. data/module/gems/commander-4.1.3/spec/core_ext/array_spec.rb +20 -0
  58. data/module/gems/commander-4.1.3/spec/core_ext/object_spec.rb +21 -0
  59. data/module/gems/commander-4.1.3/spec/help_formatters/terminal_spec.rb +67 -0
  60. data/module/gems/commander-4.1.3/spec/runner_spec.rb +526 -0
  61. data/module/gems/commander-4.1.3/spec/spec_helper.rb +59 -0
  62. data/module/gems/commander-4.1.3/spec/ui_spec.rb +30 -0
  63. data/module/gems/hello.rb +1 -0
  64. data/module/gems/highline-1.6.19/.gitignore +2 -0
  65. data/module/gems/highline-1.6.19/AUTHORS +3 -0
  66. data/module/gems/highline-1.6.19/CHANGELOG +346 -0
  67. data/module/gems/highline-1.6.19/COPYING +340 -0
  68. data/module/gems/highline-1.6.19/INSTALL +55 -0
  69. data/module/gems/highline-1.6.19/LICENSE +7 -0
  70. data/module/gems/highline-1.6.19/README.rdoc +63 -0
  71. data/module/gems/highline-1.6.19/Rakefile +50 -0
  72. data/module/gems/highline-1.6.19/TODO +6 -0
  73. data/module/gems/highline-1.6.19/examples/ansi_colors.rb +38 -0
  74. data/module/gems/highline-1.6.19/examples/asking_for_arrays.rb +18 -0
  75. data/module/gems/highline-1.6.19/examples/basic_usage.rb +75 -0
  76. data/module/gems/highline-1.6.19/examples/color_scheme.rb +32 -0
  77. data/module/gems/highline-1.6.19/examples/get_character.rb +12 -0
  78. data/module/gems/highline-1.6.19/examples/limit.rb +12 -0
  79. data/module/gems/highline-1.6.19/examples/menus.rb +65 -0
  80. data/module/gems/highline-1.6.19/examples/overwrite.rb +19 -0
  81. data/module/gems/highline-1.6.19/examples/page_and_wrap.rb +322 -0
  82. data/module/gems/highline-1.6.19/examples/password.rb +7 -0
  83. data/module/gems/highline-1.6.19/examples/repeat_entry.rb +21 -0
  84. data/module/gems/highline-1.6.19/examples/trapping_eof.rb +22 -0
  85. data/module/gems/highline-1.6.19/examples/using_readline.rb +17 -0
  86. data/module/gems/highline-1.6.19/highline.gemspec +37 -0
  87. data/module/gems/highline-1.6.19/lib/highline.rb +1012 -0
  88. data/module/gems/highline-1.6.19/lib/highline/color_scheme.rb +134 -0
  89. data/module/gems/highline-1.6.19/lib/highline/compatibility.rb +16 -0
  90. data/module/gems/highline-1.6.19/lib/highline/import.rb +41 -0
  91. data/module/gems/highline-1.6.19/lib/highline/menu.rb +398 -0
  92. data/module/gems/highline-1.6.19/lib/highline/question.rb +475 -0
  93. data/module/gems/highline-1.6.19/lib/highline/simulate.rb +48 -0
  94. data/module/gems/highline-1.6.19/lib/highline/string_extensions.rb +131 -0
  95. data/module/gems/highline-1.6.19/lib/highline/style.rb +181 -0
  96. data/module/gems/highline-1.6.19/lib/highline/system_extensions.rb +222 -0
  97. data/module/gems/highline-1.6.19/setup.rb +1360 -0
  98. data/module/gems/highline-1.6.19/site/.cvsignore +1 -0
  99. data/module/gems/highline-1.6.19/site/highline.css +65 -0
  100. data/module/gems/highline-1.6.19/site/images/logo.png +0 -0
  101. data/module/gems/highline-1.6.19/site/index.html +58 -0
  102. data/module/gems/highline-1.6.19/test/string_methods.rb +32 -0
  103. data/module/gems/highline-1.6.19/test/tc_color_scheme.rb +96 -0
  104. data/module/gems/highline-1.6.19/test/tc_highline.rb +1128 -0
  105. data/module/gems/highline-1.6.19/test/tc_import.rb +52 -0
  106. data/module/gems/highline-1.6.19/test/tc_menu.rb +439 -0
  107. data/module/gems/highline-1.6.19/test/tc_string_extension.rb +20 -0
  108. data/module/gems/highline-1.6.19/test/tc_string_highline.rb +38 -0
  109. data/module/gems/highline-1.6.19/test/tc_style.rb +567 -0
  110. data/module/gems/highline-1.6.19/test/ts_all.rb +16 -0
  111. data/module/latest_specs.4.8 +0 -0
  112. data/module/latest_specs.4.8.gz +0 -0
  113. data/module/prerelease_specs.4.8 +0 -0
  114. data/module/prerelease_specs.4.8.gz +0 -0
  115. data/module/specs.4.8 +0 -0
  116. data/module/specs.4.8.gz +0 -0
  117. data/samples/blather/restlike/Gemfile +4 -0
  118. data/samples/blather/restlike/cmd.yml +1 -0
  119. data/samples/blather/restlike/lib/blather.rb +9 -0
  120. data/samples/blather/restlike/lib/blather/dsl/api.rb +78 -0
  121. data/samples/blather/restlike/lib/blather/dsl/call.rb +13 -0
  122. data/samples/blather/restlike/lib/blather/dsl/client.rb +58 -0
  123. data/samples/blather/restlike/lib/blather/dsl/config.rb +11 -0
  124. data/samples/blather/restlike/lib/blather/dsl/extraDSL.rb +163 -0
  125. data/samples/blather/restlike/lib/blather/meta/require.rb +8 -0
  126. data/samples/blather/restlike/lib/blather/meta/xmpp.yml +5 -0
  127. data/samples/blather/restlike/lib/blather/vendors/xmpp_default.rb +27 -0
  128. data/samples/blather/restlike/readme +2 -0
  129. data/samples/grape/init/Gemfile +2 -0
  130. data/samples/grape/init/cmd.yml +3 -0
  131. data/samples/grape/init/config.ru +2 -0
  132. data/samples/grape/init/docs/grape/documentation.txt +939 -0
  133. data/samples/grape/init/docs/grape/generate_rest_routes.rb +37 -0
  134. data/samples/grape/init/docs/grape/ls_routes.rb +31 -0
  135. data/samples/grape/init/lib/grape.rb +4 -0
  136. data/samples/grape/init/lib/grape/meta/subclasses.rb +20 -0
  137. data/samples/grape/init/lib/grape/xpath/app.rb +30 -0
  138. data/samples/grape/init/lib/grape/xpath/ruotes.rb +6 -0
  139. data/samples/grape/init/readme +1 -0
  140. data/samples/grape/readme +29 -0
  141. data/samples/grape/vendor/lib/grape/vendors/v1/rest.rb +57 -0
  142. data/samples/mongoid/cmd.yml +1 -0
  143. data/samples/mongoid/init/Gemfile +3 -0
  144. data/samples/mongoid/init/cmd.yml +2 -0
  145. data/samples/mongoid/init/docs/mongoid/ModelsRelations.rb +11 -0
  146. data/samples/mongoid/init/docs/mongoid/documents.xls +0 -0
  147. data/samples/mongoid/init/docs/mongoid/generate_modelsToDocs.rb +25 -0
  148. data/samples/mongoid/init/docs/mongoid/modelsToDocs.rb +25 -0
  149. data/samples/mongoid/init/docs/mongoid/relations.txt +1354 -0
  150. data/samples/mongoid/init/lib/mongoid.rb +44 -0
  151. data/samples/mongoid/init/lib/mongoid/dsl/extraDSL_CRUD.rb +446 -0
  152. data/samples/mongoid/init/lib/mongoid/dsl/extraDSL_MP.rb +517 -0
  153. data/samples/mongoid/init/lib/mongoid/dsl/init.rb +37 -0
  154. data/samples/mongoid/init/lib/mongoid/dsl/params.rb +67 -0
  155. data/samples/mongoid/init/lib/mongoid/meta/banned.rb +147 -0
  156. data/samples/mongoid/init/lib/mongoid/meta/control.yml +13 -0
  157. data/samples/mongoid/init/lib/mongoid/meta/mongoid.yml +6 -0
  158. data/samples/mongoid/init/lib/mongoid/meta/mpatch.rb +14 -0
  159. data/samples/mongoid/model/lib/mongoid/models/model.rb +28 -0
  160. data/samples/mongoid/readme +33 -0
  161. data/samples/rack/init/Gemfile +10 -0
  162. data/samples/rack/init/cmd.yml +2 -0
  163. data/samples/rack/init/config.ru +1 -0
  164. data/samples/rack/init/docs/rack/rake introducing.txt +60 -0
  165. data/samples/rack/init/docs/rack/webservers/Thin +43 -0
  166. data/samples/rack/init/docs/rack/webservers/ebb +72 -0
  167. data/samples/rack/init/docs/rack/webservers/fcgi +103 -0
  168. data/samples/rack/init/docs/rack/webservers/mongrel +74 -0
  169. data/samples/rack/init/docs/rack/webservers/passenger +37 -0
  170. data/samples/rack/init/docs/rack/webservers/scgi +188 -0
  171. data/samples/rack/init/lib/rack.rb +1 -0
  172. data/samples/rack/init/lib/rack/meta/webserver/thin.rb +45 -0
  173. data/samples/rack/init/lib/rack/meta/webserver/thin.yml +6 -0
  174. data/samples/rack/init/server.rb +0 -0
  175. data/samples/rack/readme +13 -0
  176. data/samples/rest_client/init/Gemfile +5 -0
  177. data/samples/rest_client/init/boot.rb +2 -0
  178. data/samples/rest_client/init/cmd.yml +1 -0
  179. data/samples/rest_client/init/config/rest_client/defaults.rb +16 -0
  180. data/samples/rest_client/init/docs/rest_client/simple overlook +251 -0
  181. data/samples/rest_client/init/test/rest_client/rest_dsl.rb +5 -0
  182. data/samples/rest_client/readme +7 -0
  183. data/samples/scripts/lines_counter/lines_number.rb +32 -0
  184. data/samples/scripts/lines_counter/readme +5 -0
  185. data/samples/scripts/readme +1 -0
  186. metadata +197 -7
  187. data/lib/clone/cms.rb +0 -56
  188. data/lib/clone/ext.rb +0 -77
  189. data/sample/test.rb +0 -30
@@ -0,0 +1,37 @@
1
+ require_relative File.join("..","..","boot.rb")
2
+ write_out_array = Array.new
3
+ write_out_array.push "REST::API ROUTES:\n"
4
+ write_out_array.push "\nTable Of Contents\n================="
5
+
6
+ array_of_hash = Array.new
7
+ REST::API.routes.map do |route|
8
+ array_of_hash.push({:method => route.route_method.to_s, :path => route.route_path.to_s})
9
+ end
10
+ contents_array= Array.new
11
+ array_of_hash.each do |hash|
12
+ separator_str= String.new
13
+ if hash[:method].to_s == "POST" || hash[:method].to_s == "DELETE"
14
+ separator_str= "\t\t "
15
+ else
16
+ separator_str= "\t\t\t "
17
+ end
18
+ contents_array.push "#{hash[:method]}#{separator_str}#{hash[:path]}"
19
+ end
20
+ write_out_array.push contents_array.join("\n")
21
+ write_out_array.push "\nExplanations\n============"
22
+ REST::API.routes.map do |route|
23
+ new_docs_element= Array.new
24
+ new_docs_element.push "Method: #{route.route_method}"
25
+ new_docs_element.push "Path: #{route.route_path}"
26
+ new_docs_element.push "description: #{route.route_description}"
27
+ if route.route_params.count == 0
28
+ new_docs_element.push "No specified or special params"
29
+ else
30
+ route.route_params.each do |key,value|
31
+ new_docs_element.push " -#{key}: #{value}"
32
+ end
33
+ end
34
+ new_docs_element.push "\n"
35
+ write_out_array.push new_docs_element.join("\n")
36
+ end
37
+ File.new("routes_docs.txt","w").write write_out_array.join("\n")
@@ -0,0 +1,31 @@
1
+ require_relative File.join("..","..","boot.rb")
2
+ write_out_array = Array.new
3
+ write_out_array.push "REST::API ROUTES:\n"
4
+ write_out_array.push "\nTable Of Contents\n================="
5
+
6
+ array_of_hash = Array.new
7
+ REST::API.routes.map do |route|
8
+ array_of_hash.push({:method => route.route_method.to_s, :path => route.route_path.to_s})
9
+ end
10
+ contents_array= Array.new
11
+ array_of_hash.sort_by!{|hash| hash[:method]}.each do |hash|
12
+ contents_array.push "#{hash[:method]} | #{hash[:path]}"
13
+ end
14
+ write_out_array.push contents_array.join("\n")
15
+ write_out_array.push "\nExplanations\n============"
16
+ REST::API.routes.map do |route|
17
+ new_docs_element= Array.new
18
+ new_docs_element.push "Method: #{route.route_method}"
19
+ new_docs_element.push "Path: #{route.route_path}"
20
+ new_docs_element.push "description: #{route.route_description}"
21
+ if route.route_params.count == 0
22
+ new_docs_element.push "No specified or special params"
23
+ else
24
+ route.route_params.each do |key,value|
25
+ new_docs_element.push " -#{key}: #{value}"
26
+ end
27
+ end
28
+ new_docs_element.push "\n"
29
+ write_out_array.push new_docs_element.join("\n")
30
+ end
31
+ puts write_out_array.join("\n")
@@ -0,0 +1,4 @@
1
+
2
+ ### Load Grape API parts
3
+ require_relative_directory File.join "grape","vendors"
4
+ require_relative_directory File.join "grape","xpath"
@@ -0,0 +1,20 @@
1
+ module Grape
2
+ # The API class is the primary entry point for
3
+ # creating Grape APIs.Users should subclass this
4
+ # class in order to build an API.
5
+ class API
6
+
7
+ def self.inherited(subclass)
8
+ @classes ||= Array.new
9
+ @classes.push subclass.name.constantize
10
+
11
+ subclass.reset!
12
+ subclass.logger = logger.clone
13
+ end
14
+
15
+ def self.classes
16
+ @classes
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,30 @@
1
+ #encoding: UTF-8
2
+ module REST
3
+ class API < Grape::API
4
+
5
+ ### defaults
6
+ begin
7
+ ### exclude array
8
+ exclude_list = [
9
+ self
10
+ ]
11
+ end
12
+
13
+ ### mount components
14
+ begin
15
+ Grape::API.classes.each do |component|
16
+ if !exclude_list.include? component
17
+ begin
18
+ if component.class == Class
19
+ mount component
20
+ else
21
+ mount component.constantize
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+
29
+ end
30
+ end
@@ -0,0 +1,6 @@
1
+ if $DEBUG
2
+ puts "\n\nREST::API ROUTES:"
3
+ REST::API.routes.map do |route|
4
+ putsf 8,"\t#{route.route_method}","#{route.route_path}"
5
+ end
6
+ end
@@ -0,0 +1 @@
1
+ generet Grape files and add new entry to the boot
@@ -0,0 +1,29 @@
1
+ REST module for making rest webserver methods!
2
+ -Ezzel REST est aplikaciokat tudsz kesziteni webszerverrer egyutt
3
+ -az aplikáció figyelni fogja a megadott routjain a beérkező kéréseket
4
+
5
+ pl.: ha a 0.0.0.0:80 on fut a webservered akkor a
6
+ GET /user .:format ez az alábbin fog figyelni ott:
7
+ 0.0.0.0:80/user
8
+
9
+ ezen az utvonalon ha bejön neki egy GET kérés válaszolni fog
10
+
11
+ REST methods:
12
+ -GET -add vissza
13
+ -POST -rogzitsed
14
+ -PUT -frissitsed a mar meglevot
15
+ -DELETE -torold azt amirol beszelunk
16
+ *ezek szimbolikus jelentesek, de ettől függetlenül a kód azt teszi
17
+ amit bele írnak.
18
+
19
+
20
+ Grape is a REST-like API micro-framework for Ruby.
21
+ It's designed to run on Rack or complement
22
+ existing web application frameworks such as Rails
23
+ and Sinatra by providing a simple DSL to easily develop RESTful APIs.
24
+ It has built-in support for common conventions,
25
+ including multiple formats, subdomain/prefix restriction,
26
+ content negotiation, versioning and much more.
27
+
28
+ Grape APIs are Rack applications that are created by
29
+ subclassing Grape::API.
@@ -0,0 +1,57 @@
1
+ #encoding: UTF-8
2
+ module REST
3
+ class CLASS < Grape::API
4
+
5
+ version 'v1',
6
+ using: :header,
7
+ vendor: 'APP'
8
+
9
+ default_format :txt
10
+ format :txt
11
+ #format :xml
12
+ #format :json
13
+
14
+
15
+ resource :RESOURCE do
16
+
17
+ desc ""
18
+ params do
19
+ #requires :id, type: Integer
20
+ #optional :text, type: String, regexp: /^[a-z]+$/
21
+ #group :media do
22
+ # requires :url
23
+ #end
24
+ end
25
+ get do
26
+
27
+ end
28
+
29
+
30
+ desc ""
31
+ post do
32
+
33
+ end
34
+
35
+
36
+ desc ""
37
+ put do
38
+
39
+ end
40
+
41
+
42
+ desc ""
43
+ delete do
44
+
45
+ end
46
+
47
+
48
+ end
49
+ end
50
+ end
51
+
52
+
53
+
54
+
55
+
56
+
57
+
@@ -0,0 +1 @@
1
+ helper: init
@@ -0,0 +1,3 @@
1
+ ### Mongoid is an ODM (Object Document Mapper)
2
+ ## Framework for MongoDB, written in Ruby.
3
+ gem "mongoid", "~> 3.1.4"
@@ -0,0 +1,2 @@
1
+ helper: init
2
+ mongoid: model
@@ -0,0 +1,11 @@
1
+ require_relative File.join("..","..","boot.rb")
2
+
3
+
4
+ begin
5
+ relations_array = Array.new
6
+ Mongoid::Document.classes.each do |class_name|
7
+ relations_array.push class_name.constantize.getPaths[0]
8
+ end
9
+ relations_array= relations_array.sort_by{ |hsh| hsh.values }
10
+ end
11
+ puts relations_array
@@ -0,0 +1,25 @@
1
+ require_relative File.join("..","..","boot.rb")
2
+
3
+ write_out_array= Array.new
4
+ begin
5
+ puts "\n"
6
+ separator= "="*0#*99
7
+ Mongoid::Document.classes.each do |class_name|
8
+ puts separator
9
+ write_out_array.push separator
10
+ puts "the model name:#{class_name}"
11
+ write_out_array.push "the model name:#{class_name}"
12
+ begin
13
+ puts "the embeds model:"+(class_name.constantize.getPaths).inspect
14
+ write_out_array.push "the embeds model:"+(class_name.constantize.getPaths).inspect
15
+ rescue NoMethodError
16
+ end
17
+ class_name.constantize.properties.each do |key,value|
18
+ printf "%-78s %s\n", "The field name: #{key}", "field type: #{value}"
19
+ write_out_array.push("The field name: #{key},\t field type: #{value}")
20
+ end
21
+ puts separator
22
+ write_out_array.push separator
23
+ end
24
+ end
25
+ File.new("models_docs.txt","w").write write_out_array.join("\n")
@@ -0,0 +1,25 @@
1
+ require_relative File.join("..","..","boot.rb")
2
+
3
+ write_out_array= Array.new
4
+ begin
5
+ puts "\n"
6
+ separator= "="*0#*99
7
+ Mongoid::Document.classes.each do |class_name|
8
+ puts separator
9
+ write_out_array.push separator
10
+ puts "the model name:#{class_name}"
11
+ write_out_array.push "the model name:#{class_name}"
12
+ begin
13
+ puts "the embeds model:"+(class_name.constantize.getPaths).inspect
14
+ write_out_array.push "the embeds model:"+(class_name.constantize.getPaths).inspect
15
+ rescue NoMethodError
16
+ end
17
+ class_name.constantize.properties.each do |key,value|
18
+ printf "%-78s %s\n", "The field name: #{key}", "field type: #{value}"
19
+ write_out_array.push("The field name: #{key},\t field type: #{value}")
20
+ end
21
+ puts separator
22
+ write_out_array.push separator
23
+ end
24
+ end
25
+ File.new("models_docs.txt","w").write write_out_array.join("\n")
@@ -0,0 +1,1354 @@
1
+
2
+ Common Behaviour
3
+
4
+ Attributes
5
+
6
+ All relations contain a target, which is the proxied document or documents, a base which is the document the relation hangs off, and metadata which provides information about the relation.
7
+
8
+
9
+ class Person
10
+ include Mongoid::Document
11
+ embeds_many :addresses
12
+ end
13
+
14
+ person.addresses = [ address ]
15
+ person.addresses.target # returns [ address ]
16
+ person.addresses.base # returns person
17
+ person.addresses.metadata # returns the metadata
18
+
19
+
20
+ Extensions
21
+
22
+ All relations can have extensions, which provides a way to add application specific functionality to the relation. They are defined by providing a block to the relation definition.
23
+
24
+
25
+ class Person
26
+ include Mongoid::Document
27
+ embeds_many :addresses do
28
+ def find_by_country(country)
29
+ where(country: country).first
30
+ end
31
+ def chinese
32
+ @target.select { |address| address.country == "China"}
33
+ end
34
+ end
35
+ end
36
+
37
+ person.addresses.find_by_country("Mongolia") # returns address
38
+ person.addresses.chinese # returns [ address ]
39
+
40
+
41
+ Custom Relation Names
42
+
43
+ You can name your relations whatever you like, but if the class cannot be inferred by Mongoid from the name, and neither can the opposite side you'll want to provide the macro with some additional options to tell Mongoid how to hook them up.
44
+
45
+
46
+ class Lush
47
+ include Mongoid::Document
48
+ embeds_one :whiskey, class_name: "Drink", inverse_of: :alcoholic
49
+ end
50
+
51
+ class Drink
52
+ include Mongoid::Document
53
+ embedded_in :alcoholic, class_name: "Lush", inverse_of: :whiskey
54
+ end
55
+
56
+
57
+ Validations
58
+
59
+ It is important to note that by default, Mongoid will validate the children of any relation that are loaded into memory via a validates_associated. The relations that this applies to are:
60
+ •embeds_many
61
+ •embeds_one
62
+ •has_many
63
+ •has_one
64
+ •has_and_belongs_to_many
65
+
66
+
67
+ If you do not want this behavior, you may turn it off when defining the relation.
68
+
69
+
70
+ class Person
71
+ include Mongoid::Document
72
+
73
+ embeds_many :addresses, validate: false
74
+ has_many :posts, validate: false
75
+ end
76
+
77
+
78
+ Polymorphism
79
+
80
+ When a child embedded document can belong to more than one type of parent document, you can tell Mongoid to support this by adding the as option to the definition on the parents, and the polymorphic option on the child. On the child object, an additional field will be stored that indicates the type of the parent.
81
+
82
+
83
+
84
+ Polymorphic behavior is allowed on all relations with the exception of has_and_belongs_to_many.
85
+
86
+
87
+
88
+ class Band
89
+ include Mongoid::Document
90
+ embeds_many :photos, as: :photographic
91
+ has_one :address, as: :addressable
92
+ end
93
+
94
+ class Photo
95
+ include Mongoid::Document
96
+ embedded_in :photographic, polymorphic: true
97
+ end
98
+
99
+ class Address
100
+ include Mongoid::Document
101
+ belongs_to :addressable, polymorphic: true
102
+ end
103
+
104
+
105
+ Cascading Callbacks
106
+
107
+ If you want the embedded document callbacks to fire when calling a persistence operation on its parent, you will need to provide the cascade callbacks option to the relation.
108
+
109
+
110
+
111
+ Cascading callbacks is only available on embeds_one and embeds_many relations.
112
+
113
+
114
+
115
+ class Band
116
+ include Mongoid::Document
117
+ embeds_many :albums, cascade_callbacks: true
118
+ embeds_one :label, cascade_callbacks: true
119
+ end
120
+
121
+ band.save # Fires all save callbacks on the band, albums, and label.
122
+
123
+
124
+ Dependent Behaviour
125
+
126
+ You can provided dependent options to referenced associations to instruct Mongoid how to handle situations where one side of the relation is deleted, or is attempted to be deleted. The options are as follows:
127
+ •:delete: Delete the child document.
128
+ •:destroy: Destroy the child document.
129
+ •:nullify: Orphan the child document.
130
+ •:restrict: Raise an error if the child is not empty.
131
+
132
+
133
+
134
+ Dependent options are only available on referenced relations.
135
+
136
+
137
+ The default behavior of each association when no dependent option is provided is to nullify.
138
+
139
+
140
+ class Band
141
+ include Mongoid::Document
142
+ has_many :albums, dependent: :delete
143
+ belongs_to :label, dependent: :nullify
144
+ end
145
+
146
+ class Album
147
+ include Mongoid::Document
148
+ belongs_to :band
149
+ end
150
+
151
+ class Label
152
+ include Mongoid::Document
153
+ has_many :bands, dependent: :restrict
154
+ end
155
+
156
+ label = Label.first
157
+ label.bands.push(Band.first)
158
+ label.delete # Raises an error since bands is not empty.
159
+
160
+ Band.first.delete # Will delete all associated albums.
161
+
162
+
163
+ Autosaving
164
+
165
+ One core difference between Mongoid and Active Record from a behavior standpoint is that Mongoid does not automatically save child relations for relational associations. This is for performance reasons.
166
+
167
+ To enable an autosave on a relational association (embedded associations do not need this since they are actually part of the parent in the database) add the autosave option to the relation.
168
+
169
+
170
+ Note that autosave functionality will automatically be added to a relation when using accepts_nested_attributes_for or validating presence of the relation.
171
+
172
+
173
+ class Band
174
+ include Mongoid::Document
175
+ has_many :albums, autosave: true
176
+ end
177
+
178
+ band = Band.first
179
+ band.albums.build(name: "101")
180
+ band.save #=> Will save the album as well.
181
+
182
+
183
+ Recursive Embedding
184
+
185
+ A document can recursively embed itself using recursively_embeds_one or recursively_embeds_many, which provides accessors for the parent and children via parent_ and child_ methods.
186
+
187
+
188
+
189
+ Recursive options are only available on embedded relations.
190
+
191
+
192
+
193
+ class Tag
194
+ include Mongoid::Document
195
+ recursively_embeds_many
196
+ end
197
+
198
+ root = Tag.new(name: "programming")
199
+ child_one = root.child_tags.build
200
+ child_two = root.child_tags.build
201
+
202
+ root.child_tags # [ child_one, child_two ]
203
+ child_one.parent_tag # [ root ]
204
+ child_two.parent_tag # [ root ]
205
+
206
+ class Node
207
+ include Mongoid::Document
208
+ recursively_embeds_one
209
+ end
210
+
211
+ root = Node.new
212
+ child = Node.new
213
+ root.child_node = child
214
+
215
+ root.child # child
216
+ child.parent_node # root
217
+
218
+
219
+ Existence Predicates
220
+
221
+ All relations have existence predicates on them in the form of name? and has_name? to check if the relation is blank.
222
+
223
+
224
+ class Band
225
+ include Mongoid::Document
226
+ embeds_one :label
227
+ embeds_many :albums
228
+ end
229
+
230
+ band.label?
231
+ band.has_label?
232
+ band.albums?
233
+ band.has_albums?
234
+
235
+
236
+ Autobuilding
237
+
238
+ One to one relations (embeds_one, has_one) have an autobuild option which tells Mongoid to instantiate a new document when the relation is accessed and it is nil
239
+
240
+
241
+
242
+ Existence predicates will not trigger an autobuild, so they will properly return false if the document is not present.
243
+
244
+
245
+
246
+ class Band
247
+ include Mongoid::Document
248
+ embeds_one :label, autobuild: true
249
+ has_one :producer, autobuild: true
250
+ end
251
+
252
+ band = Band.new
253
+ band.label # Returns a new empty label.
254
+ band.producer # Returns a new empty producer.
255
+
256
+
257
+ Touching
258
+
259
+ Any belongs_to relation, no matter where it hangs off from, can take an optional :touch option which will call the touch method on it and any parent relations with the option defined when the base document calls #touch.
260
+
261
+
262
+ class Band
263
+ include Mongoid::Document
264
+ belongs_to :label, touch: true
265
+ end
266
+
267
+ band = Band.first
268
+ band.touch #=> Calls touch on the parent label.
269
+
270
+
271
+ Metadata
272
+
273
+ All relations in Mongoid contain metadata that holds information about the relation in question, and is a valuable tool for third party developers to use to extend Mongoid.
274
+
275
+ You can access the metadata of the relation in a few different ways.
276
+
277
+
278
+ # Get the metadata for a named relation from the class or document.
279
+ Model.reflect_on_association(:relation_name)
280
+ model.reflect_on_association(:relation_name)
281
+
282
+ # Get the metadata that the current object has in its relation.
283
+ model.metadata
284
+
285
+ # Get the metadata with a specific relation itself on a specific
286
+ # document.
287
+ person.addresses.metadata
288
+
289
+
290
+ The Metadata Object
291
+
292
+ The metadata object itself contains more information than one might know what to do with, and is useful for developers of extensions to Mongoid.
293
+
294
+
295
+ Method
296
+
297
+ Description
298
+
299
+
300
+ Metadata#as Returns the name of the parent to a polymorphic child.
301
+ Metadata#as? Returns whether or not an as option exists.
302
+ Metadata#autobuilding? Returns whether or not the relation is autobuilding.
303
+ Metadata#autosaving? Returns whether or not the relation is autosaving.
304
+ Metadata#cascading_callbacks? Returns whether the relation has callbacks cascaded down from the parent.
305
+ Metadata#class_name Returns the class name of the proxied document.
306
+ Metadata#cyclic? Returns whether the relation is a cyclic relation.
307
+ Metadata#dependent Returns the relation's dependent option.
308
+ Metadata#dependent? Returns whether the relation is a dependent relation.
309
+ Metadata#destructive? Returns true if the relation has a dependent delete or destroy.
310
+ Metadata#embedded? Returns whether the relation is embedded in another document.
311
+ Metadata#forced_nil_inverse? Returns whether the relation has a nil inverse defined.
312
+ Metadata#foreign_key Returns the name of the foreign key field.
313
+ Metadata#foreign_key_check Returns the name of the foreign key field dirty check method.
314
+ Metadata#foreign_key_setter Returns the name of the foreign key field setter.
315
+ Metadata#indexed? Returns whether the foreign key is auto indexed.
316
+ Metadata#inverses Returns the names of all inverse relation.
317
+ Metadata#inverse Returns the name of a single inverse relation.
318
+ Metadata#inverse_class_name Returns the class name of the relation on the inverse side.
319
+ Metadata#inverse_foreign_key Returns the name of the foreign key field on the inverse side.
320
+ Metadata#inverse_klass Returns the class of the relation on the inverse side.
321
+ Metadata#inverse_metadata Returns the metadata of the relation on the inverse side.
322
+ Metadata#inverse_of Returns the explicitly defined name of the inverse relation.
323
+ Metadata#inverse_of? Returns whether an inverse_of option is defined.
324
+ Metadata#inverse_setter Returns the name of the method used to set the inverse.
325
+ Metadata#inverse_type Returns the name for the polymorphic type field of the inverse.
326
+ Metadata#inverse_type_setter Returns the name for the polymorphic type field setter of the inverse.
327
+ Metadata#key Returns the name of the field in the attributes hash to use to get the relation.
328
+ Metadata#klass Returns the class of the proxied documents in the relation.
329
+ Metadata#macro Returns the relation's macro.
330
+ Metadata#name Returns the relation name.
331
+ Metadata#options Returns self, for API compatibility with Active Record.
332
+ Metadata#order Returns the custom sorting options on the relation.
333
+ Metadata#order? Returns whether custom sorting options are set.
334
+ Metadata#polymorphic? Returns whether the relation is polymorphic.
335
+ Metadata#setter Returns the name of the field to set the relation.
336
+ Metadata#store_as Returns the name of the attribute to store an embedded relation in.
337
+ Metadata#touchable? Returns whether or not the relation has a touch option.
338
+ Metadata#type Returns the name of the field to get the polymorphic type.
339
+ Metadata#type_setter Returns the name of the field to set the polymorphic type.
340
+ Metadata#validate? Returns whether the relation has an associated validation.
341
+ Metadata#versioned? Returns whether the relation is an embedded version.
342
+
343
+ Embedded 1-1
344
+
345
+ One to one relationships where the children are embedded in the parent document are defined using Mongoid's embeds_one and embedded_in macros.
346
+
347
+ Defining
348
+
349
+ The parent document of the relation should use the embeds_one macro to indicate is has 1 embedded child, where the document that is embedded uses embedded_in.
350
+
351
+
352
+ class Band
353
+ include Mongoid::Document
354
+ embeds_one :label
355
+ end
356
+
357
+ class Label
358
+ include Mongoid::Document
359
+ field :name, type: String
360
+ embedded_in :band
361
+ end
362
+
363
+
364
+
365
+
366
+ Definitions are required on both sides to the relation in order for it to work properly.
367
+
368
+
369
+ Storage
370
+
371
+ Documents that are embedded using the embeds_one macro are stored as a hash inside the parent in the parent's database collection.
372
+
373
+
374
+ {
375
+ "_id" : ObjectId("4d3ed089fb60ab534684b7e9"),
376
+ "label" : {
377
+ "_id" : ObjectId("4d3ed089fb60ab534684b7e0"),
378
+ "name" : "Mute",
379
+ }
380
+ }
381
+
382
+
383
+ You can optionally tell Mongoid to store the embedded document in a different attribute other than the name, by providing a :store_as option.
384
+
385
+
386
+ class Band
387
+ include Mongoid::Document
388
+ embeds_one :label, store_as: "lab"
389
+ end
390
+
391
+
392
+ Operations
393
+
394
+ Once the relation is defined, the following operations are available, and the following table shows any database operations that are performed if applicable. The previously defined models will be used for example code.
395
+
396
+
397
+ Operation
398
+
399
+ Mongoid
400
+
401
+ Moped
402
+
403
+
404
+ Model#{name}
405
+ Get the embedded document.
406
+
407
+
408
+ band.label
409
+
410
+ Model#{name}=
411
+ Set the embedded document. If the parent document is persisted, then the child will be atomically saved immediately. If setting to nil then the child will be deleted.
412
+
413
+
414
+ band.label = Label.new(name: "Mute")
415
+
416
+ band.label = nil
417
+
418
+
419
+ collections[:bands].find(...).
420
+ update(
421
+ "$set" => { label: { name: "Mute" }}
422
+ )
423
+
424
+ collections[:bands].find(...).
425
+ update("$unset" => { label: true })
426
+
427
+
428
+ Model#{parent_name}
429
+ Get the parent document from the child.
430
+
431
+
432
+ label.band
433
+
434
+ Model#{parent_name}=
435
+ Set the parent document from the child.
436
+
437
+
438
+ label.band = Band.new
439
+
440
+ Model#build_{name}
441
+ Build a new document on the relation.
442
+
443
+
444
+ band.build_label(name: "Mute")
445
+
446
+ label.build_band(name: "Depeche Mode")
447
+
448
+ Model#create_{name}
449
+ Create a new document from either side of the relation. This persists the child immediately if executing from the parent, and persists the entire tree if executed from the child.
450
+
451
+
452
+ band.create_label(name: "Mute")
453
+
454
+ label.create_band({
455
+ name: "Depeche Mode"
456
+ })
457
+
458
+
459
+ collections[:bands].find(...).
460
+ update(
461
+ "$set" => { label: { name: "Mute" }}
462
+ )
463
+
464
+ collections[:bands].
465
+ insert({
466
+ name: "Depeche Mode",
467
+ label: { name: "Mute" }
468
+ })
469
+
470
+
471
+
472
+ Embedded 1-n
473
+
474
+ One to many relationships where the children are embedded in the parent document are defined using Mongoid's embeds_many and embedded_in macros.
475
+
476
+ Defining
477
+
478
+ The parent document of the relation should use the embeds_many macro to indicate it has n number of embedded children, where the document that is embedded uses embedded_in.
479
+
480
+
481
+ class Band
482
+ include Mongoid::Document
483
+ embeds_many :albums
484
+ end
485
+
486
+ class Album
487
+ include Mongoid::Document
488
+ field :name, type: String
489
+ embedded_in :band
490
+ end
491
+
492
+
493
+
494
+
495
+ Definitions are required on both sides to the relation in order for it to work properly.
496
+
497
+
498
+ Storage
499
+
500
+ Documents that are embedded using the embeds_many macro are stored as an array of hashes inside the parent in the parent's database collection.
501
+
502
+
503
+ {
504
+ "_id" : ObjectId("4d3ed089fb60ab534684b7e9"),
505
+ "albums" : [
506
+ {
507
+ "_id" : ObjectId("4d3ed089fb60ab534684b7e0"),
508
+ "name" : "Violator",
509
+ }
510
+ ]
511
+ }
512
+
513
+
514
+ You can optionally tell Mongoid to store the embedded document in a different attribute other than the name, by providing a :store_as option.
515
+
516
+
517
+ class Band
518
+ include Mongoid::Document
519
+ embeds_many :albums, store_as: "albs"
520
+ end
521
+
522
+
523
+ Operations
524
+
525
+ Once the relation is defined, the following operations are available, and the following table shows any database operations that are performed if applicable. The previously defined models will be used for example code.
526
+
527
+
528
+ Operation
529
+
530
+ Mongoid
531
+
532
+ Moped
533
+
534
+
535
+ Model#{name}
536
+ Get the embedded documents.
537
+
538
+
539
+ band.albums
540
+
541
+ Model#{name}=
542
+ Set the embedded documents. If the parent document is persisted, then the child will be atomically saved immediately. If setting to nil or [] then the children will be deleted.
543
+
544
+
545
+ band.albums = [ Album.new(name: "Violator") ]
546
+
547
+ band.albums = nil
548
+ band.albums = []
549
+
550
+
551
+ collections[:bands].find(...).
552
+ update(
553
+ "$set" => { albums: [{ name: "Violator" }]}
554
+ )
555
+
556
+ collections[:bands].find(...).
557
+ update("$unset" => { albums: true })
558
+
559
+
560
+ Model#{parent_name}
561
+ Get the parent document from any child.
562
+
563
+
564
+ album.band
565
+
566
+ Model#{parent_name}=
567
+ Set the parent document from a child.
568
+
569
+
570
+ album.band = Band.new
571
+
572
+ Model#{name}.<<
573
+ Model#{name}.push
574
+ Push a new document onto the relation. If the parent is persisted, then the child documents will be automatically saved.
575
+
576
+
577
+ band.albums << Album.new(name: "Violator")
578
+ band.albums.push(Album.new(name: "Violator"))
579
+
580
+
581
+ collections[:bands].find(...).
582
+ update(
583
+ "$push" => { albums: { name: "Violator" }}
584
+ )
585
+
586
+ Model#{name}.concat
587
+ Push multiple documents onto the relation. If the parent is persisted, then the child documents will be automatically saved. Note that while batch operations limit the number of database calls to a single one for the new documents, it is in fact at least 2x slower from the Ruby side. This is due to the fact that 2 iterations over all documents must occur to ensure that all the before callbacks run before the db hit, and that all after callbacks have to wait until after.
588
+
589
+
590
+ band.albums.concat(
591
+ Album.new(name: "Violator"),
592
+ Album.new(name: "101")
593
+ )
594
+
595
+
596
+ collections[:bands].find(...).
597
+ update(
598
+ "$pushAll" => {
599
+ albums: [{ name: "Violator" }, { name: "101" }]
600
+ }
601
+ )
602
+
603
+ Model#{name}.build
604
+ Model#{name}.new
605
+ Build a new document in the relation with the provided attributes. Does not save the new document.
606
+
607
+
608
+ band.albums.build(name: "Violator")
609
+ band.albums.new(name: "Violator")
610
+
611
+ Model#{name}.create
612
+ Model#{name}.create!
613
+ Create a new document in the relation with the provided attributes and saves. With the bang version an error will be raised if validation fails.
614
+
615
+
616
+ band.albums.create(name: "Violator")
617
+ band.albums.create!(name: "Violator")
618
+
619
+
620
+ collections[:bands].find(...).
621
+ update(
622
+ "$push" => { albums: { name: "Violator" }}
623
+ )
624
+
625
+ Model#{name}.clear
626
+ Model#{name}.delete_all
627
+ Deletes all documents from the relation, without running any callbacks.
628
+
629
+
630
+ band.albums.clear
631
+ band.albums.delete_all
632
+ band.albums.delete_all(name: "Violator")
633
+ band.albums.
634
+ where(name: "Violator").delete_all
635
+
636
+
637
+ collections[:bands].find(...).
638
+ update(
639
+ "$pullAll" => { albums: [{ name: "Violator" }]}
640
+ )
641
+
642
+ Model#{name}.destroy_all
643
+ Deletes all documents from the relation, while running the destroy callbacks.
644
+
645
+
646
+ band.albums.destroy_all
647
+ band.albums.destroy_all(name: "Violator")
648
+ band.albums.
649
+ where(name: "Violator").destroy_all
650
+
651
+
652
+ collections[:bands].find(...).
653
+ update(
654
+ "$pullAll" => { albums: [{ name: "Violator" }]}
655
+ )
656
+
657
+ Model#{name}.delete
658
+ Deletes the matching document from the relation.
659
+
660
+
661
+ band.albums.delete(album)
662
+
663
+
664
+ collections[:bands].find(...).
665
+ update(
666
+ "$pull" => { albums: { name: "Violator" }}
667
+ )
668
+
669
+ Model#{name}.pop
670
+ Deletes the provided number of documents, defaulting to 1.
671
+
672
+
673
+ band.albums.pop
674
+ band.albums.pop(1)
675
+
676
+
677
+ collections[:bands].find(...).
678
+ update(
679
+ "$pullAll" => { albums: [{ name: "Violator" }]}
680
+ )
681
+
682
+ Model#{name}.find
683
+ Return documents in the relation with matching ids. Will raise an error if all the ids are not found by default.
684
+
685
+
686
+ band.albums.find(id)
687
+ band.albums.find(id_one, id_two)
688
+
689
+ Model#{name}.find_or_create_by
690
+ Search for the document in the relation, and if not found create a newly persisted one.
691
+
692
+
693
+ band.albums.
694
+ find_or_create_by(name: "Violator")
695
+
696
+
697
+ collections[:bands].find(...).
698
+ update(
699
+ "$push" => { albums: { name: "Violator" }}
700
+ )
701
+
702
+ Model#{name}.find_or_initialize_by
703
+ Search for the document in the relation, and if not found add a new one.
704
+
705
+
706
+ band.albums.
707
+ find_or_initialize_by(name: "Violator")
708
+
709
+ Model#{name}.where
710
+ Find matching documents in the relation. This can be any criteria method, not just where.
711
+
712
+
713
+ band.albums.where(name: "Violator")
714
+
715
+ Model#{name}.exists?
716
+ Returns whether or not the relation has any documents.
717
+
718
+
719
+ band.albums.exists?
720
+
721
+
722
+ Referenced 1-1
723
+
724
+ One to one relationships where the children are referenced in the parent document are defined using Mongoid's has_one and belongs_to macros.
725
+
726
+ Defining
727
+
728
+ The parent document of the relation should use the has_one macro to indicate is has 1 referenced child, where the document that is referenced in it uses belongs_to.
729
+
730
+
731
+ class Band
732
+ include Mongoid::Document
733
+ has_one :studio
734
+ end
735
+
736
+ class Studio
737
+ include Mongoid::Document
738
+ field :name, type: String
739
+ belongs_to :band
740
+ end
741
+
742
+
743
+ Definitions are required on both sides to the relation in order for it to work properly, unless one of the models is embedded.
744
+
745
+ Storage
746
+
747
+ When defining a relation of this nature, each document is stored in its respective collection, but the child document contains a "foreign key" reference to the parent.
748
+
749
+
750
+ # The parent band document.
751
+ { "_id" : ObjectId("4d3ed089fb60ab534684b7e9") }
752
+
753
+ # The child studio document.
754
+ {
755
+ "_id" : ObjectId("4d3ed089fb60ab534684b7f1"),
756
+ "band_id" : ObjectId("4d3ed089fb60ab534684b7e9")
757
+ }
758
+
759
+
760
+ Operations
761
+
762
+ Once the relation is defined, the following operations are available, and the following table shows any database operations that are performed if applicable. The previously defined models will be used for example code.
763
+
764
+
765
+ Operation
766
+
767
+ Mongoid
768
+
769
+ Moped
770
+
771
+
772
+ Model#{name}
773
+ Get the child document.
774
+
775
+
776
+ band.studio
777
+
778
+ Model#{name}=
779
+ Set the child document. If the parent document is persisted, then the child will be saved immediately. If setting to nil then the child will be deleted.
780
+
781
+
782
+ band.studio = Studio.new(name: "Abbey Road")
783
+
784
+ band.studio = nil
785
+
786
+
787
+ collections[:studios].insert(
788
+ { name: "Abbey Road", band_id: ... }
789
+ )
790
+
791
+ collections[:studios].find(...).remove
792
+
793
+
794
+ Model#{parent_name}
795
+ Get the parent document from the child.
796
+
797
+
798
+ studio.band
799
+
800
+ Model#{parent_name}=
801
+ Set the parent document from the child.
802
+
803
+
804
+ studio.band = Band.new
805
+
806
+ Model#build_{name}
807
+ Build a new document on the relation. This does not save the new document.
808
+
809
+
810
+ band.build_studio(name: "Abbey Road")
811
+
812
+ studio.build_band(name: "Depeche Mode")
813
+
814
+ Model#create_{name}
815
+ Create a new document from either side of the relation. This persists the child immediately if executing from the parent, and persists the parent if executed from the child.
816
+
817
+
818
+ band.create_studio(name: "Abbey Road")
819
+
820
+ studio.create_band(name: "Depeche Mode")
821
+
822
+
823
+ collections[:studios].insert(
824
+ { name: "Abbey Road", band_id: ... }
825
+ )
826
+
827
+ collections[:bands].insert(
828
+ { name: "Depeche Mode" }
829
+ )
830
+
831
+
832
+
833
+ Referenced 1-n
834
+
835
+ One to many relationships where the children are stored in a separate collection from the parent document are defined using Mongoid's has_many and belongs_to macros. This exhibits similar behavior to Active Record.
836
+
837
+ Defining
838
+
839
+ The parent document of the relation should use the has_many macro to indicate is has n number of referenced children, where the document that is referenced uses belongs_to.
840
+
841
+
842
+ class Band
843
+ include Mongoid::Document
844
+ has_many :members
845
+ end
846
+
847
+ class Member
848
+ include Mongoid::Document
849
+ field :name, type: String
850
+ belongs_to :band
851
+ end
852
+
853
+
854
+ Definitions are required on both sides to the relation in order for it to work properly, unless one of the models is embedded.
855
+
856
+ Storage
857
+
858
+ When defining a relation of this nature, each document is stored in its respective collection, but the child document contains a "foreign key" reference to the parent.
859
+
860
+
861
+ # The parent band document.
862
+ { "_id" : ObjectId("4d3ed089fb60ab534684b7e9") }
863
+
864
+ # The child member document.
865
+ {
866
+ "_id" : ObjectId("4d3ed089fb60ab534684b7f1"),
867
+ "band_id" : ObjectId("4d3ed089fb60ab534684b7e9")
868
+ }
869
+
870
+
871
+ Operations
872
+
873
+ Once the relation is defined, the following operations are available, and the following table shows any database operations that are performed if applicable. The previously defined models will be used for example code.
874
+
875
+
876
+ Operation
877
+
878
+ Mongoid
879
+
880
+ Moped
881
+
882
+
883
+ Model#{name}
884
+ Get the related documents.
885
+
886
+
887
+ band.members
888
+
889
+ Model#{name}=
890
+ Set the related documents. If the parent document is persisted, then the child will be saved immediately. If setting to nil or [] then the children will be deleted.
891
+
892
+
893
+ band.members = [ Member.new(name: "Fletch") ]
894
+
895
+ band.members = nil
896
+ band.members = []
897
+
898
+
899
+ collections[:members].insert(
900
+ { name: "Fletch", band_id: ... }
901
+ )
902
+
903
+ collections[:members].find(...).remove
904
+
905
+ Model#{name}_ids
906
+ Get the related document ids.
907
+
908
+
909
+ band.member_ids
910
+
911
+ Model#{name}_ids=
912
+ Set the related document ids.
913
+
914
+
915
+ band.member_ids = [ id ]
916
+
917
+ Model#{parent_name}
918
+ Get the parent document from any child.
919
+
920
+
921
+ member.band
922
+
923
+ Model#{parent_name}=
924
+ Set the parent document from a child.
925
+
926
+
927
+ member.band = Band.new
928
+
929
+ Model#{name}.<<
930
+ Model#{name}.push
931
+ Push a new document onto the relation. If the parent is persisted, then the child documents will be automatically saved.
932
+
933
+
934
+ band.members << Member.new(name: "Fletch")
935
+ band.members.push(Member.new(name: "Fletch"))
936
+
937
+
938
+ collections[:members].insert(
939
+ { name: "Fletch", band_id: ... }
940
+ )
941
+
942
+ Model#{name}.concat
943
+ Push multiple documents onto the relation. If the parent is persisted, then the child documents will be automatically saved in a single batch. Note that while batch operations limit the number of database calls to a single one for the new documents, it is in fact at least 2x slower from the Ruby side. This is due to the fact that 2 iterations over all documents must occur to ensure that all the before callbacks run before the db hit, and that all after callbacks have to wait until after.
944
+
945
+
946
+ band.members.concat(
947
+ Member.new(name: "Fletch"),
948
+ Member.new(name: "Martin")
949
+ )
950
+
951
+
952
+ collections[:members].insert([
953
+ { name: "Fletch", band_id: ... },
954
+ { name: "Martin", band_id: ... }
955
+ ])
956
+
957
+ Model#{name}.build
958
+ Model#{name}.new
959
+ Build a new document in the relation with the provided attributes. Does not save the new document.
960
+
961
+
962
+ band.members.build(name: "Fletch")
963
+ band.members.new(name: "Fletch")
964
+
965
+ Model#{name}.create
966
+ Model#{name}.create!
967
+ Create a new document in the relation with the provided attributes and saves. With the bang version an error will be raised if validation fails.
968
+
969
+
970
+ band.members.create(name: "Fletch")
971
+ band.members.create!(name: "Fletch")
972
+
973
+
974
+ collections[:members].insert(
975
+ { name: "Fletch", band_id: ... }
976
+ )
977
+
978
+ Model#{name}.clear
979
+ Model#{name}.delete_all
980
+ Deletes all documents from the relation, without running any callbacks.
981
+
982
+
983
+ band.members.clear
984
+ band.members.delete_all
985
+ band.members.delete_all(name: "Fletch")
986
+ band.members.
987
+ where(name: "Fletch").delete_all
988
+
989
+
990
+ collections[:members].find(band_id: ...).remove_all
991
+
992
+ collections[:members].
993
+ find(band_id: ..., name: "Fletch").remove_all
994
+
995
+ Model#{name}.destroy_all
996
+ Deletes all documents from the relation, while running the destroy callbacks.
997
+
998
+
999
+ band.members.destroy_all
1000
+ band.members.destroy_all(name: "Fletch")
1001
+ band.members.
1002
+ where(name: "Fletch").destroy_all
1003
+
1004
+
1005
+ collections[:members].find(band_id: ...).remove_all
1006
+
1007
+ collections[:members].
1008
+ find(band_id: ..., name: "Fletch").remove_all
1009
+
1010
+ Model#{name}.delete
1011
+ Deletes the matching document from the relation.
1012
+
1013
+
1014
+ band.members.delete(member)
1015
+
1016
+
1017
+ collections[:members].
1018
+ find(band_id: ..., name: "Fletch").remove
1019
+
1020
+ Model#{name}.find
1021
+ Return documents in the relation with matching ids. Will raise an error if all the ids are not found by default.
1022
+
1023
+
1024
+ band.members.find(id)
1025
+
1026
+ band.members.find(id_one, id_two)
1027
+
1028
+
1029
+ collections[:members].find({
1030
+ band_id: ..., _id: id
1031
+ })
1032
+
1033
+ collections[:members].find({
1034
+ band_id: ..., _id: { "$in" => [ id_one, id_two ] }
1035
+ })
1036
+
1037
+ Model#{name}.find_or_create_by
1038
+ Search for the document in the relation, and if not found create a newly persisted one.
1039
+
1040
+
1041
+ band.members.
1042
+ find_or_create_by(name: "Fletch")
1043
+
1044
+
1045
+ collections[:members].find({
1046
+ band_id: ..., name: "Fletch"
1047
+ })
1048
+ collections[:members].insert(
1049
+ { name: "Fletch", band_id: ... }
1050
+ )
1051
+
1052
+ Model#{name}.find_or_initialize_by
1053
+ Search for the document in the relation, and if not found add a new one.
1054
+
1055
+
1056
+ band.members.
1057
+ find_or_initialize_by(name: "Fletch")
1058
+
1059
+
1060
+ collections[:members].find({
1061
+ band_id: ..., name: "Fletch"
1062
+ })
1063
+
1064
+ Model#{name}.where
1065
+ Find matching documents in the relation. This can be any criteria method, not just where.
1066
+
1067
+
1068
+ band.members.where(name: "Fletch")
1069
+
1070
+
1071
+ collections[:members].find({
1072
+ band_id: ..., name: "Fletch"
1073
+ })
1074
+
1075
+ Model#{name}.exists?
1076
+ Returns whether or not the relation has any documents.
1077
+
1078
+
1079
+ band.members.exists?
1080
+
1081
+
1082
+ collections[:members].find(band_id: ...).count
1083
+
1084
+
1085
+
1086
+ Referenced n-n
1087
+
1088
+ Many to many relationships where the inverse documents are stored in a separate collection from the base document are defined using Mongoid's has_and_belongs_to_many macro. This exhibits similar behavior to Active Record with the exception that no join collection is needed, the foreign key ids are stored as arrays on either side of the relation.
1089
+
1090
+ Defining
1091
+
1092
+ Both sides of the relation use the same macro.
1093
+
1094
+
1095
+ class Band
1096
+ include Mongoid::Document
1097
+ has_and_belongs_to_many :tags
1098
+ end
1099
+
1100
+ class Tag
1101
+ include Mongoid::Document
1102
+ field :name, type: String
1103
+ has_and_belongs_to_many :bands
1104
+ end
1105
+
1106
+
1107
+ You can create a one sided many to many if you want to mimic a has_many that stores the keys as an array on the parent.
1108
+
1109
+
1110
+ class Band
1111
+ include Mongoid::Document
1112
+ has_and_belongs_to_many :tags, inverse_of: nil
1113
+ end
1114
+
1115
+ class Tag
1116
+ include Mongoid::Document
1117
+ field :name, type: String
1118
+ end
1119
+
1120
+
1121
+ Storage
1122
+
1123
+ When defining a relation of this nature, each document is stored in its respective collection, and each document contains a "foreign key" reference to the other in the form of an array.
1124
+
1125
+
1126
+ # The band document.
1127
+ {
1128
+ "_id" : ObjectId("4d3ed089fb60ab534684b7e9"),
1129
+ "tag_ids" : [ ObjectId("4d3ed089fb60ab534684b7f2") ]
1130
+ }
1131
+
1132
+ # The tag document.
1133
+ {
1134
+ "_id" : ObjectId("4d3ed089fb60ab534684b7f2"),
1135
+ "band_ids" : [ ObjectId("4d3ed089fb60ab534684b7e9") ]
1136
+ }
1137
+
1138
+
1139
+ Operations
1140
+
1141
+ Once the relation is defined, the following operations are available, and the following table shows any database operations that are performed if applicable. The previously defined models will be used for example code.
1142
+
1143
+
1144
+
1145
+ Many to many relations require usually double the amount of hits to the database to keep both sides of the relation in sync, since keys are stored on both sides. Due to this they are slower and should be used with caution.
1146
+
1147
+
1148
+
1149
+ Operation
1150
+
1151
+ Mongoid
1152
+
1153
+ Moped
1154
+
1155
+
1156
+ Model#{name}
1157
+ Get the related documents.
1158
+
1159
+
1160
+ band.tags
1161
+
1162
+ Model#{name}=
1163
+ Set the related documents. If the parent document is persisted, then the child will be saved immediately along with the parent to keep the keys consistent. If setting to nil or [] then the children will be deleted.
1164
+
1165
+
1166
+ band.tags = [ Tag.new(name: "electro") ]
1167
+
1168
+ band.tags = nil
1169
+ band.tags = []
1170
+
1171
+
1172
+ collections[:tags].insert(
1173
+ { name: "electro", band_ids: ... }
1174
+ )
1175
+ collections[:bands].find(...).
1176
+ update("$push" => { tag_ids: ... })
1177
+
1178
+ collections[:tags].find(...).remove
1179
+ collections[:bands].find(...).
1180
+ update("$pull" => { tag_ids: ... })
1181
+
1182
+ Model#{name}.<<
1183
+ Model#{name}.push
1184
+ Push a new document onto the relation. If the parent is persisted, then the child documents will be automatically saved.
1185
+
1186
+
1187
+ band.tags << Tag.new(name: "electro")
1188
+ band.tags.push(Tag.new(name: "electro"))
1189
+
1190
+
1191
+ collections[:tags].insert(
1192
+ { name: "electro", band_ids: ... }
1193
+ )
1194
+ collections[:bands].find(...).
1195
+ update("$push" => { tag_ids: ... })
1196
+
1197
+ Model#{name}.concat
1198
+ Push multiple documents onto the relation. If the parent is persisted, then the child documents will be automatically saved in a single batch. Note that while batch operations limit the number of database calls to a single one for the new documents, it is in fact at least 2x slower from the Ruby side. This is due to the fact that 2 iterations over all documents must occur to ensure that all the before callbacks run before the db hit, and that all after callbacks have to wait until after.
1199
+
1200
+
1201
+ band.tags.concat(
1202
+ Tag.new(name: "electro"),
1203
+ Tag.new(name: "new wave")
1204
+ )
1205
+
1206
+
1207
+ collections[:tags].insert([
1208
+ { name: "electro", band_ids: ... },
1209
+ { name: "new wave", band_ids: ... }
1210
+ ])
1211
+ collections[:bands].find(...).
1212
+ update("$pushAll" => { tag_ids: ... })
1213
+
1214
+ Model#{name}.build
1215
+ Model#{name}.new
1216
+ Build a new document in the relation with the provided attributes. Does not save the new document.
1217
+
1218
+
1219
+ band.tags.build(name: "electro")
1220
+ band.tags.new(name: "electro")
1221
+
1222
+ Model#{name}.create
1223
+ Model#{name}.create!
1224
+ Create a new document in the relation with the provided attributes and saves. With the bang version an error will be raised if validation fails.
1225
+
1226
+
1227
+ band.tags.create(name: "electro")
1228
+ band.tags.create!(name: "electro")
1229
+
1230
+
1231
+ collections[:tags].insert(
1232
+ { name: "electro", band_ids: ... }
1233
+ )
1234
+ collections[:bands].find(...).
1235
+ update("$push" => { tag_ids: ... })
1236
+
1237
+ Model#{name}.clear
1238
+ Model#{name}.delete_all
1239
+ Deletes all documents from the relation, without running any callbacks.
1240
+
1241
+
1242
+ band.tags.clear
1243
+ band.tags.delete_all
1244
+ band.tags.delete_all(name: "electro")
1245
+ band.tags.
1246
+ where(name: "electro").delete_all
1247
+
1248
+
1249
+ collections[:tags].find(_id: { "$in" => ... }).remove_all
1250
+ collections[:bands].find(...).
1251
+ update("$pullAll" => { tag_ids: ... })
1252
+
1253
+ collections[:tags].
1254
+ find(_id: { "$in" => ... }, name: "electro").remove_all
1255
+ collections[:bands].find(...).
1256
+ update("$pullAll" => { tag_ids: ... })
1257
+
1258
+ Model#{name}.destroy_all
1259
+ Deletes all documents from the relation, while running the destroy callbacks.
1260
+
1261
+
1262
+ band.tags.destroy_all
1263
+ band.tags.destroy_all(name: "electro")
1264
+ band.tags.
1265
+ where(name: "electro").destroy_all
1266
+
1267
+
1268
+ collections[:tags].find(_id: { "$in" => ... }).remove_all
1269
+ collections[:bands].find(...).
1270
+ update("$pullAll" => { tag_ids: ... })
1271
+
1272
+ collections[:tags].
1273
+ find(_id: { "$in" => ... }, name: "electro").remove_all
1274
+ collections[:bands].find(...).
1275
+ update("$pullAll" => { tag_ids: ... })
1276
+
1277
+ Model#{name}.delete
1278
+ Deletes the matching document from the relation.
1279
+
1280
+
1281
+ band.tags.delete(tag)
1282
+
1283
+
1284
+ collections[:tags].
1285
+ find(_id: { "$in" => ... }, name: "electro").remove
1286
+ collections[:bands].find(...).
1287
+ update("$pull" => { tag_ids: ... })
1288
+
1289
+ Model#{name}.find
1290
+ Return documents in the relation with matching ids. Will raise an error if all the ids are not found by default.
1291
+
1292
+
1293
+ band.tags.find(id)
1294
+
1295
+ band.tags.find(id_one, id_two)
1296
+
1297
+
1298
+ collections[:tags].find({
1299
+ _id: { "$in" => ... }, { "$and" => [{ _id: id }] }
1300
+ })
1301
+
1302
+ collections[:tags].find({
1303
+ _id: { "$in" => ... },
1304
+ { "$and" => [{ _id: { "$in" => [ id_one, id_two ]}}] }
1305
+ })
1306
+
1307
+ Model#{name}.find_or_create_by
1308
+ Search for the document in the relation, and if not found create a newly persisted one.
1309
+
1310
+
1311
+ band.tags.
1312
+ find_or_create_by(name: "electro")
1313
+
1314
+
1315
+ collections[:tags].find({
1316
+ _id: { "$in" => ... }, name: "electro"
1317
+ })
1318
+ collections[:tags].insert(
1319
+ { name: "electro", band_ids: ... }
1320
+ )
1321
+
1322
+ Model#{name}.find_or_initialize_by
1323
+ Search for the document in the relation, and if not found add a new one.
1324
+
1325
+
1326
+ band.tags.
1327
+ find_or_initialize_by(name: "electro")
1328
+
1329
+
1330
+ collections[:tags].find({
1331
+ _id: { "$in" => ... }, name: "electro"
1332
+ })
1333
+
1334
+ Model#{name}.where
1335
+ Find matching documents in the relation. This can be any criteria method, not just where.
1336
+
1337
+
1338
+ band.tags.where(name: "electro")
1339
+
1340
+
1341
+ collections[:tags].find({
1342
+ _id: { "$in" => ... }, name: "electro"
1343
+ })
1344
+
1345
+ Model#{name}.exists?
1346
+ Returns whether or not the relation has any documents.
1347
+
1348
+
1349
+ band.tags.exists?
1350
+
1351
+
1352
+ collections[:tags].
1353
+ find(_id: { "$in" => ... }).count
1354
+