activerecord 5.0.6 → 6.0.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (358) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +638 -2023
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +8 -6
  5. data/examples/performance.rb +31 -29
  6. data/examples/simple.rb +5 -3
  7. data/lib/active_record/aggregations.rb +249 -246
  8. data/lib/active_record/association_relation.rb +24 -13
  9. data/lib/active_record/associations/alias_tracker.rb +24 -33
  10. data/lib/active_record/associations/association.rb +119 -56
  11. data/lib/active_record/associations/association_scope.rb +94 -94
  12. data/lib/active_record/associations/belongs_to_association.rb +58 -42
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
  14. data/lib/active_record/associations/builder/association.rb +18 -25
  15. data/lib/active_record/associations/builder/belongs_to.rb +43 -54
  16. data/lib/active_record/associations/builder/collection_association.rb +7 -18
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +42 -61
  18. data/lib/active_record/associations/builder/has_many.rb +4 -0
  19. data/lib/active_record/associations/builder/has_one.rb +37 -1
  20. data/lib/active_record/associations/builder/singular_association.rb +4 -0
  21. data/lib/active_record/associations/collection_association.rb +80 -252
  22. data/lib/active_record/associations/collection_proxy.rb +158 -121
  23. data/lib/active_record/associations/foreign_association.rb +9 -0
  24. data/lib/active_record/associations/has_many_association.rb +23 -29
  25. data/lib/active_record/associations/has_many_through_association.rb +58 -44
  26. data/lib/active_record/associations/has_one_association.rb +59 -54
  27. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  28. data/lib/active_record/associations/join_dependency/join_association.rb +38 -90
  29. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
  31. data/lib/active_record/associations/join_dependency.rb +134 -176
  32. data/lib/active_record/associations/preloader/association.rb +84 -125
  33. data/lib/active_record/associations/preloader/through_association.rb +82 -75
  34. data/lib/active_record/associations/preloader.rb +90 -102
  35. data/lib/active_record/associations/singular_association.rb +12 -45
  36. data/lib/active_record/associations/through_association.rb +26 -14
  37. data/lib/active_record/associations.rb +1603 -1592
  38. data/lib/active_record/attribute_assignment.rb +54 -60
  39. data/lib/active_record/attribute_decorators.rb +38 -15
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +12 -7
  41. data/lib/active_record/attribute_methods/dirty.rb +179 -109
  42. data/lib/active_record/attribute_methods/primary_key.rb +86 -91
  43. data/lib/active_record/attribute_methods/query.rb +4 -3
  44. data/lib/active_record/attribute_methods/read.rb +21 -49
  45. data/lib/active_record/attribute_methods/serialization.rb +30 -7
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -64
  47. data/lib/active_record/attribute_methods/write.rb +35 -33
  48. data/lib/active_record/attribute_methods.rb +66 -106
  49. data/lib/active_record/attributes.rb +38 -24
  50. data/lib/active_record/autosave_association.rb +53 -32
  51. data/lib/active_record/base.rb +27 -24
  52. data/lib/active_record/callbacks.rb +63 -33
  53. data/lib/active_record/coders/json.rb +2 -0
  54. data/lib/active_record/coders/yaml_column.rb +11 -11
  55. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +553 -321
  56. data/lib/active_record/connection_adapters/abstract/database_limits.rb +23 -5
  57. data/lib/active_record/connection_adapters/abstract/database_statements.rb +213 -94
  58. data/lib/active_record/connection_adapters/abstract/query_cache.rb +59 -28
  59. data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -75
  60. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  61. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +33 -27
  62. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +207 -126
  63. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +68 -80
  64. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +369 -199
  65. data/lib/active_record/connection_adapters/abstract/transaction.rb +169 -78
  66. data/lib/active_record/connection_adapters/abstract_adapter.rb +363 -202
  67. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +405 -551
  68. data/lib/active_record/connection_adapters/column.rb +41 -13
  69. data/lib/active_record/connection_adapters/connection_specification.rb +172 -138
  70. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +11 -4
  71. data/lib/active_record/connection_adapters/mysql/column.rb +8 -31
  72. data/lib/active_record/connection_adapters/mysql/database_statements.rb +143 -49
  73. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +24 -22
  74. data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -20
  75. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +50 -45
  76. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +58 -56
  77. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +70 -36
  78. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
  79. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +12 -13
  80. data/lib/active_record/connection_adapters/mysql2_adapter.rb +49 -30
  81. data/lib/active_record/connection_adapters/postgresql/column.rb +22 -7
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +60 -54
  83. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +5 -3
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +22 -10
  85. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +6 -5
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  89. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +4 -2
  91. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -3
  93. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +19 -17
  94. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  96. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -5
  98. data/lib/active_record/connection_adapters/postgresql/oid/{json.rb → oid.rb} +6 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +31 -9
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +34 -30
  101. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  102. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
  103. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +9 -4
  104. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid.rb +24 -21
  107. data/lib/active_record/connection_adapters/postgresql/quoting.rb +95 -35
  108. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  109. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +147 -105
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +35 -32
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +380 -300
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +26 -25
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +10 -6
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +382 -275
  116. data/lib/active_record/connection_adapters/schema_cache.rb +46 -12
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +13 -8
  118. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +3 -1
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +74 -19
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +3 -8
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +254 -262
  126. data/lib/active_record/connection_adapters/statement_pool.rb +9 -7
  127. data/lib/active_record/connection_handling.rb +159 -40
  128. data/lib/active_record/core.rb +202 -162
  129. data/lib/active_record/counter_cache.rb +57 -28
  130. data/lib/active_record/database_configurations/database_config.rb +37 -0
  131. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  132. data/lib/active_record/database_configurations/url_config.rb +79 -0
  133. data/lib/active_record/database_configurations.rb +233 -0
  134. data/lib/active_record/define_callbacks.rb +22 -0
  135. data/lib/active_record/dynamic_matchers.rb +87 -86
  136. data/lib/active_record/enum.rb +60 -23
  137. data/lib/active_record/errors.rb +114 -18
  138. data/lib/active_record/explain.rb +4 -3
  139. data/lib/active_record/explain_registry.rb +3 -1
  140. data/lib/active_record/explain_subscriber.rb +9 -4
  141. data/lib/active_record/fixture_set/file.rb +13 -8
  142. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  143. data/lib/active_record/fixture_set/render_context.rb +17 -0
  144. data/lib/active_record/fixture_set/table_row.rb +153 -0
  145. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  146. data/lib/active_record/fixtures.rb +195 -502
  147. data/lib/active_record/gem_version.rb +4 -2
  148. data/lib/active_record/inheritance.rb +151 -97
  149. data/lib/active_record/insert_all.rb +179 -0
  150. data/lib/active_record/integration.rb +116 -25
  151. data/lib/active_record/internal_metadata.rb +15 -18
  152. data/lib/active_record/legacy_yaml_adapter.rb +4 -2
  153. data/lib/active_record/locking/optimistic.rb +78 -87
  154. data/lib/active_record/locking/pessimistic.rb +18 -6
  155. data/lib/active_record/log_subscriber.rb +48 -29
  156. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  157. data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
  158. data/lib/active_record/middleware/database_selector.rb +75 -0
  159. data/lib/active_record/migration/command_recorder.rb +143 -97
  160. data/lib/active_record/migration/compatibility.rb +174 -56
  161. data/lib/active_record/migration/join_table.rb +8 -6
  162. data/lib/active_record/migration.rb +367 -300
  163. data/lib/active_record/model_schema.rb +145 -139
  164. data/lib/active_record/nested_attributes.rb +214 -201
  165. data/lib/active_record/no_touching.rb +10 -1
  166. data/lib/active_record/null_relation.rb +13 -34
  167. data/lib/active_record/persistence.rb +442 -72
  168. data/lib/active_record/query_cache.rb +15 -14
  169. data/lib/active_record/querying.rb +36 -23
  170. data/lib/active_record/railtie.rb +128 -36
  171. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  172. data/lib/active_record/railties/console_sandbox.rb +2 -0
  173. data/lib/active_record/railties/controller_runtime.rb +34 -33
  174. data/lib/active_record/railties/databases.rake +309 -177
  175. data/lib/active_record/readonly_attributes.rb +5 -4
  176. data/lib/active_record/reflection.rb +211 -249
  177. data/lib/active_record/relation/batches/batch_enumerator.rb +3 -1
  178. data/lib/active_record/relation/batches.rb +99 -52
  179. data/lib/active_record/relation/calculations.rb +211 -172
  180. data/lib/active_record/relation/delegation.rb +67 -65
  181. data/lib/active_record/relation/finder_methods.rb +208 -247
  182. data/lib/active_record/relation/from_clause.rb +2 -8
  183. data/lib/active_record/relation/merger.rb +78 -61
  184. data/lib/active_record/relation/predicate_builder/array_handler.rb +20 -14
  185. data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
  186. data/lib/active_record/relation/predicate_builder/base_handler.rb +4 -3
  187. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +6 -4
  188. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
  189. data/lib/active_record/relation/predicate_builder/range_handler.rb +7 -18
  190. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  191. data/lib/active_record/relation/predicate_builder.rb +86 -104
  192. data/lib/active_record/relation/query_attribute.rb +33 -2
  193. data/lib/active_record/relation/query_methods.rb +458 -329
  194. data/lib/active_record/relation/record_fetch_warning.rb +5 -3
  195. data/lib/active_record/relation/spawn_methods.rb +8 -7
  196. data/lib/active_record/relation/where_clause.rb +111 -95
  197. data/lib/active_record/relation/where_clause_factory.rb +6 -11
  198. data/lib/active_record/relation.rb +429 -318
  199. data/lib/active_record/result.rb +69 -39
  200. data/lib/active_record/runtime_registry.rb +5 -3
  201. data/lib/active_record/sanitization.rb +83 -99
  202. data/lib/active_record/schema.rb +7 -14
  203. data/lib/active_record/schema_dumper.rb +71 -69
  204. data/lib/active_record/schema_migration.rb +15 -5
  205. data/lib/active_record/scoping/default.rb +93 -95
  206. data/lib/active_record/scoping/named.rb +45 -25
  207. data/lib/active_record/scoping.rb +20 -19
  208. data/lib/active_record/secure_token.rb +4 -2
  209. data/lib/active_record/serialization.rb +2 -0
  210. data/lib/active_record/statement_cache.rb +63 -28
  211. data/lib/active_record/store.rb +121 -41
  212. data/lib/active_record/suppressor.rb +4 -1
  213. data/lib/active_record/table_metadata.rb +26 -20
  214. data/lib/active_record/tasks/database_tasks.rb +276 -85
  215. data/lib/active_record/tasks/mysql_database_tasks.rb +54 -90
  216. data/lib/active_record/tasks/postgresql_database_tasks.rb +78 -47
  217. data/lib/active_record/tasks/sqlite_database_tasks.rb +34 -16
  218. data/lib/active_record/test_databases.rb +23 -0
  219. data/lib/active_record/test_fixtures.rb +224 -0
  220. data/lib/active_record/timestamp.rb +70 -35
  221. data/lib/active_record/touch_later.rb +7 -4
  222. data/lib/active_record/transactions.rb +133 -149
  223. data/lib/active_record/translation.rb +3 -1
  224. data/lib/active_record/type/adapter_specific_registry.rb +44 -45
  225. data/lib/active_record/type/date.rb +2 -0
  226. data/lib/active_record/type/date_time.rb +2 -0
  227. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  228. data/lib/active_record/type/hash_lookup_type_map.rb +5 -3
  229. data/lib/active_record/type/internal/timezone.rb +2 -0
  230. data/lib/active_record/type/json.rb +30 -0
  231. data/lib/active_record/type/serialized.rb +16 -8
  232. data/lib/active_record/type/text.rb +11 -0
  233. data/lib/active_record/type/time.rb +2 -1
  234. data/lib/active_record/type/type_map.rb +13 -15
  235. data/lib/active_record/type/unsigned_integer.rb +17 -0
  236. data/lib/active_record/type.rb +23 -17
  237. data/lib/active_record/type_caster/connection.rb +17 -12
  238. data/lib/active_record/type_caster/map.rb +5 -4
  239. data/lib/active_record/type_caster.rb +4 -2
  240. data/lib/active_record/validations/absence.rb +2 -0
  241. data/lib/active_record/validations/associated.rb +3 -1
  242. data/lib/active_record/validations/length.rb +2 -0
  243. data/lib/active_record/validations/presence.rb +4 -2
  244. data/lib/active_record/validations/uniqueness.rb +29 -42
  245. data/lib/active_record/validations.rb +7 -4
  246. data/lib/active_record/version.rb +3 -1
  247. data/lib/active_record.rb +36 -22
  248. data/lib/arel/alias_predication.rb +9 -0
  249. data/lib/arel/attributes/attribute.rb +37 -0
  250. data/lib/arel/attributes.rb +22 -0
  251. data/lib/arel/collectors/bind.rb +24 -0
  252. data/lib/arel/collectors/composite.rb +31 -0
  253. data/lib/arel/collectors/plain_string.rb +20 -0
  254. data/lib/arel/collectors/sql_string.rb +20 -0
  255. data/lib/arel/collectors/substitute_binds.rb +28 -0
  256. data/lib/arel/crud.rb +42 -0
  257. data/lib/arel/delete_manager.rb +18 -0
  258. data/lib/arel/errors.rb +9 -0
  259. data/lib/arel/expressions.rb +29 -0
  260. data/lib/arel/factory_methods.rb +49 -0
  261. data/lib/arel/insert_manager.rb +49 -0
  262. data/lib/arel/math.rb +45 -0
  263. data/lib/arel/nodes/and.rb +32 -0
  264. data/lib/arel/nodes/ascending.rb +23 -0
  265. data/lib/arel/nodes/binary.rb +52 -0
  266. data/lib/arel/nodes/bind_param.rb +36 -0
  267. data/lib/arel/nodes/case.rb +55 -0
  268. data/lib/arel/nodes/casted.rb +50 -0
  269. data/lib/arel/nodes/comment.rb +29 -0
  270. data/lib/arel/nodes/count.rb +12 -0
  271. data/lib/arel/nodes/delete_statement.rb +45 -0
  272. data/lib/arel/nodes/descending.rb +23 -0
  273. data/lib/arel/nodes/equality.rb +18 -0
  274. data/lib/arel/nodes/extract.rb +24 -0
  275. data/lib/arel/nodes/false.rb +16 -0
  276. data/lib/arel/nodes/full_outer_join.rb +8 -0
  277. data/lib/arel/nodes/function.rb +44 -0
  278. data/lib/arel/nodes/grouping.rb +8 -0
  279. data/lib/arel/nodes/in.rb +8 -0
  280. data/lib/arel/nodes/infix_operation.rb +80 -0
  281. data/lib/arel/nodes/inner_join.rb +8 -0
  282. data/lib/arel/nodes/insert_statement.rb +37 -0
  283. data/lib/arel/nodes/join_source.rb +20 -0
  284. data/lib/arel/nodes/matches.rb +18 -0
  285. data/lib/arel/nodes/named_function.rb +23 -0
  286. data/lib/arel/nodes/node.rb +50 -0
  287. data/lib/arel/nodes/node_expression.rb +13 -0
  288. data/lib/arel/nodes/outer_join.rb +8 -0
  289. data/lib/arel/nodes/over.rb +15 -0
  290. data/lib/arel/nodes/regexp.rb +16 -0
  291. data/lib/arel/nodes/right_outer_join.rb +8 -0
  292. data/lib/arel/nodes/select_core.rb +67 -0
  293. data/lib/arel/nodes/select_statement.rb +41 -0
  294. data/lib/arel/nodes/sql_literal.rb +16 -0
  295. data/lib/arel/nodes/string_join.rb +11 -0
  296. data/lib/arel/nodes/table_alias.rb +27 -0
  297. data/lib/arel/nodes/terminal.rb +16 -0
  298. data/lib/arel/nodes/true.rb +16 -0
  299. data/lib/arel/nodes/unary.rb +45 -0
  300. data/lib/arel/nodes/unary_operation.rb +20 -0
  301. data/lib/arel/nodes/unqualified_column.rb +22 -0
  302. data/lib/arel/nodes/update_statement.rb +41 -0
  303. data/lib/arel/nodes/values_list.rb +9 -0
  304. data/lib/arel/nodes/window.rb +126 -0
  305. data/lib/arel/nodes/with.rb +11 -0
  306. data/lib/arel/nodes.rb +68 -0
  307. data/lib/arel/order_predications.rb +13 -0
  308. data/lib/arel/predications.rb +257 -0
  309. data/lib/arel/select_manager.rb +271 -0
  310. data/lib/arel/table.rb +110 -0
  311. data/lib/arel/tree_manager.rb +72 -0
  312. data/lib/arel/update_manager.rb +34 -0
  313. data/lib/arel/visitors/depth_first.rb +204 -0
  314. data/lib/arel/visitors/dot.rb +297 -0
  315. data/lib/arel/visitors/ibm_db.rb +34 -0
  316. data/lib/arel/visitors/informix.rb +62 -0
  317. data/lib/arel/visitors/mssql.rb +157 -0
  318. data/lib/arel/visitors/mysql.rb +83 -0
  319. data/lib/arel/visitors/oracle.rb +159 -0
  320. data/lib/arel/visitors/oracle12.rb +66 -0
  321. data/lib/arel/visitors/postgresql.rb +110 -0
  322. data/lib/arel/visitors/sqlite.rb +39 -0
  323. data/lib/arel/visitors/to_sql.rb +889 -0
  324. data/lib/arel/visitors/visitor.rb +46 -0
  325. data/lib/arel/visitors/where_sql.rb +23 -0
  326. data/lib/arel/visitors.rb +20 -0
  327. data/lib/arel/window_predications.rb +9 -0
  328. data/lib/arel.rb +58 -0
  329. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  330. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  331. data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -35
  332. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +1 -1
  333. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +4 -2
  334. data/lib/rails/generators/active_record/migration.rb +17 -2
  335. data/lib/rails/generators/active_record/model/model_generator.rb +9 -29
  336. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +10 -1
  337. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  338. data/lib/rails/generators/active_record.rb +7 -5
  339. metadata +133 -50
  340. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  341. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  342. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  343. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  344. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  345. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  346. data/lib/active_record/associations/preloader/singular_association.rb +0 -20
  347. data/lib/active_record/attribute/user_provided_default.rb +0 -28
  348. data/lib/active_record/attribute.rb +0 -213
  349. data/lib/active_record/attribute_mutation_tracker.rb +0 -70
  350. data/lib/active_record/attribute_set/builder.rb +0 -130
  351. data/lib/active_record/attribute_set.rb +0 -110
  352. data/lib/active_record/collection_cache_key.rb +0 -50
  353. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +0 -50
  354. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  355. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  356. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
  357. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -57
  358. data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -1,10 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Associations
3
- # Association proxies in Active Record are middlemen between the object that
4
- # holds the association, known as the <tt>@owner</tt>, and the actual associated
5
- # object, known as the <tt>@target</tt>. The kind of association any proxy is
6
- # about is available in <tt>@reflection</tt>. That's an instance of the class
7
- # ActiveRecord::Reflection::AssociationReflection.
5
+ # Collection proxies in Active Record are middlemen between an
6
+ # <tt>association</tt>, and its <tt>target</tt> result set.
8
7
  #
9
8
  # For example, given
10
9
  #
@@ -14,14 +13,14 @@ module ActiveRecord
14
13
  #
15
14
  # blog = Blog.first
16
15
  #
17
- # the association proxy in <tt>blog.posts</tt> has the object in +blog+ as
18
- # <tt>@owner</tt>, the collection of its posts as <tt>@target</tt>, and
19
- # the <tt>@reflection</tt> object represents a <tt>:has_many</tt> macro.
16
+ # The collection proxy returned by <tt>blog.posts</tt> is built from a
17
+ # <tt>:has_many</tt> <tt>association</tt>, and delegates to a collection
18
+ # of posts as the <tt>target</tt>.
20
19
  #
21
- # This class delegates unknown methods to <tt>@target</tt> via
22
- # <tt>method_missing</tt>.
20
+ # This class delegates unknown methods to the <tt>association</tt>'s
21
+ # relation class via a delegate cache.
23
22
  #
24
- # The <tt>@target</tt> object is not \loaded until needed. For example,
23
+ # The <tt>target</tt> result set is not loaded until needed. For example,
25
24
  #
26
25
  # blog.posts.count
27
26
  #
@@ -30,7 +29,7 @@ module ActiveRecord
30
29
  class CollectionProxy < Relation
31
30
  def initialize(klass, association) #:nodoc:
32
31
  @association = association
33
- super klass, klass.arel_table, klass.predicate_builder
32
+ super klass
34
33
 
35
34
  extensions = association.extensions
36
35
  extend(*extensions) if extensions.any?
@@ -53,6 +52,12 @@ module ActiveRecord
53
52
  @association.loaded?
54
53
  end
55
54
 
55
+ ##
56
+ # :method: select
57
+ #
58
+ # :call-seq:
59
+ # select(*fields, &block)
60
+ #
56
61
  # Works in two ways.
57
62
  #
58
63
  # *First:* Specify a subset of fields to be selected from the result set.
@@ -75,7 +80,7 @@ module ActiveRecord
75
80
  # # #<Pet id: nil, name: "Choo-Choo">
76
81
  # # ]
77
82
  #
78
- # person.pets.select(:id, :name )
83
+ # person.pets.select(:id, :name)
79
84
  # # => [
80
85
  # # #<Pet id: 1, name: "Fancy-Fancy">,
81
86
  # # #<Pet id: 2, name: "Spook">,
@@ -100,15 +105,6 @@ module ActiveRecord
100
105
  # # #<Pet id: 2, name: "Spook", person_id: 1>,
101
106
  # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
102
107
  # # ]
103
- #
104
- # person.pets.select(:name) { |pet| pet.name =~ /oo/ }
105
- # # => [
106
- # # #<Pet id: 2, name: "Spook">,
107
- # # #<Pet id: 3, name: "Choo-Choo">
108
- # # ]
109
- def select(*fields, &block)
110
- @association.select(*fields, &block)
111
- end
112
108
 
113
109
  # Finds an object in the collection responding to the +id+. Uses the same
114
110
  # rules as ActiveRecord::Base.find. Returns ActiveRecord::RecordNotFound
@@ -136,10 +132,17 @@ module ActiveRecord
136
132
  # # #<Pet id: 2, name: "Spook", person_id: 1>,
137
133
  # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
138
134
  # # ]
139
- def find(*args, &block)
140
- @association.find(*args, &block)
135
+ def find(*args)
136
+ return super if block_given?
137
+ @association.find(*args)
141
138
  end
142
139
 
140
+ ##
141
+ # :method: first
142
+ #
143
+ # :call-seq:
144
+ # first(limit = nil)
145
+ #
143
146
  # Returns the first record, or the first +n+ records, from the collection.
144
147
  # If the collection is empty, the first form returns +nil+, and the second
145
148
  # form returns an empty array.
@@ -166,45 +169,63 @@ module ActiveRecord
166
169
  # another_person_without.pets # => []
167
170
  # another_person_without.pets.first # => nil
168
171
  # another_person_without.pets.first(3) # => []
169
- def first(*args)
170
- @association.first(*args)
171
- end
172
172
 
173
+ ##
174
+ # :method: second
175
+ #
176
+ # :call-seq:
177
+ # second()
178
+ #
173
179
  # Same as #first except returns only the second record.
174
- def second(*args)
175
- @association.second(*args)
176
- end
177
180
 
181
+ ##
182
+ # :method: third
183
+ #
184
+ # :call-seq:
185
+ # third()
186
+ #
178
187
  # Same as #first except returns only the third record.
179
- def third(*args)
180
- @association.third(*args)
181
- end
182
188
 
189
+ ##
190
+ # :method: fourth
191
+ #
192
+ # :call-seq:
193
+ # fourth()
194
+ #
183
195
  # Same as #first except returns only the fourth record.
184
- def fourth(*args)
185
- @association.fourth(*args)
186
- end
187
196
 
197
+ ##
198
+ # :method: fifth
199
+ #
200
+ # :call-seq:
201
+ # fifth()
202
+ #
188
203
  # Same as #first except returns only the fifth record.
189
- def fifth(*args)
190
- @association.fifth(*args)
191
- end
192
204
 
205
+ ##
206
+ # :method: forty_two
207
+ #
208
+ # :call-seq:
209
+ # forty_two()
210
+ #
193
211
  # Same as #first except returns only the forty second record.
194
212
  # Also known as accessing "the reddit".
195
- def forty_two(*args)
196
- @association.forty_two(*args)
197
- end
198
213
 
214
+ ##
215
+ # :method: third_to_last
216
+ #
217
+ # :call-seq:
218
+ # third_to_last()
219
+ #
199
220
  # Same as #first except returns only the third-to-last record.
200
- def third_to_last(*args)
201
- @association.third_to_last(*args)
202
- end
203
221
 
222
+ ##
223
+ # :method: second_to_last
224
+ #
225
+ # :call-seq:
226
+ # second_to_last()
227
+ #
204
228
  # Same as #first except returns only the second-to-last record.
205
- def second_to_last(*args)
206
- @association.second_to_last(*args)
207
- end
208
229
 
209
230
  # Returns the last record, or the last +n+ records, from the collection.
210
231
  # If the collection is empty, the first form returns +nil+, and the second
@@ -232,8 +253,9 @@ module ActiveRecord
232
253
  # another_person_without.pets # => []
233
254
  # another_person_without.pets.last # => nil
234
255
  # another_person_without.pets.last(3) # => []
235
- def last(*args)
236
- @association.last(*args)
256
+ def last(limit = nil)
257
+ load_target if find_from_target?
258
+ super
237
259
  end
238
260
 
239
261
  # Gives a record (or N records if a parameter is supplied) from the collection
@@ -261,8 +283,9 @@ module ActiveRecord
261
283
  # another_person_without.pets # => []
262
284
  # another_person_without.pets.take # => nil
263
285
  # another_person_without.pets.take(2) # => []
264
- def take(n = nil)
265
- @association.take(n)
286
+ def take(limit = nil)
287
+ load_target if find_from_target?
288
+ super
266
289
  end
267
290
 
268
291
  # Returns a new object of the collection type that has been instantiated
@@ -340,34 +363,6 @@ module ActiveRecord
340
363
  @association.create!(attributes, &block)
341
364
  end
342
365
 
343
- # Add one or more records to the collection by setting their foreign keys
344
- # to the association's primary key. Since #<< flattens its argument list and
345
- # inserts each record, +push+ and #concat behave identically. Returns +self+
346
- # so method calls may be chained.
347
- #
348
- # class Person < ActiveRecord::Base
349
- # has_many :pets
350
- # end
351
- #
352
- # person.pets.size # => 0
353
- # person.pets.concat(Pet.new(name: 'Fancy-Fancy'))
354
- # person.pets.concat(Pet.new(name: 'Spook'), Pet.new(name: 'Choo-Choo'))
355
- # person.pets.size # => 3
356
- #
357
- # person.id # => 1
358
- # person.pets
359
- # # => [
360
- # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
361
- # # #<Pet id: 2, name: "Spook", person_id: 1>,
362
- # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
363
- # # ]
364
- #
365
- # person.pets.concat([Pet.new(name: 'Brain'), Pet.new(name: 'Benny')])
366
- # person.pets.size # => 5
367
- def concat(*records)
368
- @association.concat(*records)
369
- end
370
-
371
366
  # Replaces this collection with +other_array+. This will perform a diff
372
367
  # and delete/add only records that have changed.
373
368
  #
@@ -474,7 +469,7 @@ module ActiveRecord
474
469
  # Pet.find(1, 2, 3)
475
470
  # # => ActiveRecord::RecordNotFound: Couldn't find all Pets with 'id': (1, 2, 3)
476
471
  def delete_all(dependent = nil)
477
- @association.delete_all(dependent)
472
+ @association.delete_all(dependent).tap { reset_scope }
478
473
  end
479
474
 
480
475
  # Deletes the records of the collection directly from the database
@@ -501,7 +496,7 @@ module ActiveRecord
501
496
  #
502
497
  # Pet.find(1) # => Couldn't find Pet with id=1
503
498
  def destroy_all
504
- @association.destroy_all
499
+ @association.destroy_all.tap { reset_scope }
505
500
  end
506
501
 
507
502
  # Deletes the +records+ supplied from the collection according to the strategy
@@ -620,7 +615,7 @@ module ActiveRecord
620
615
  # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
621
616
  # # ]
622
617
  def delete(*records)
623
- @association.delete(*records)
618
+ @association.delete(*records).tap { reset_scope }
624
619
  end
625
620
 
626
621
  # Destroys the +records+ supplied and removes them from the collection.
@@ -692,9 +687,15 @@ module ActiveRecord
692
687
  #
693
688
  # Pet.find(4, 5, 6) # => ActiveRecord::RecordNotFound: Couldn't find all Pets with 'id': (4, 5, 6)
694
689
  def destroy(*records)
695
- @association.destroy(*records)
690
+ @association.destroy(*records).tap { reset_scope }
696
691
  end
697
692
 
693
+ ##
694
+ # :method: distinct
695
+ #
696
+ # :call-seq:
697
+ # distinct(value = true)
698
+ #
698
699
  # Specifies whether the records should be unique or not.
699
700
  #
700
701
  # class Person < ActiveRecord::Base
@@ -709,17 +710,35 @@ module ActiveRecord
709
710
  #
710
711
  # person.pets.select(:name).distinct
711
712
  # # => [#<Pet name: "Fancy-Fancy">]
712
- def distinct
713
- @association.distinct
713
+ #
714
+ # person.pets.select(:name).distinct.distinct(false)
715
+ # # => [
716
+ # # #<Pet name: "Fancy-Fancy">,
717
+ # # #<Pet name: "Fancy-Fancy">
718
+ # # ]
719
+
720
+ #--
721
+ def calculate(operation, column_name)
722
+ null_scope? ? scope.calculate(operation, column_name) : super
714
723
  end
715
- alias uniq distinct
716
724
 
717
- # Count all records using SQL.
725
+ def pluck(*column_names)
726
+ null_scope? ? scope.pluck(*column_names) : super
727
+ end
728
+
729
+ ##
730
+ # :method: count
731
+ #
732
+ # :call-seq:
733
+ # count(column_name = nil, &block)
734
+ #
735
+ # Count all records.
718
736
  #
719
737
  # class Person < ActiveRecord::Base
720
738
  # has_many :pets
721
739
  # end
722
740
  #
741
+ # # This will perform the count using SQL.
723
742
  # person.pets.count # => 3
724
743
  # person.pets
725
744
  # # => [
@@ -727,17 +746,11 @@ module ActiveRecord
727
746
  # # #<Pet id: 2, name: "Spook", person_id: 1>,
728
747
  # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
729
748
  # # ]
730
- def count(column_name = nil)
731
- @association.count(column_name)
732
- end
733
-
734
- def calculate(operation, column_name)
735
- null_scope? ? scope.calculate(operation, column_name) : super
736
- end
737
-
738
- def pluck(*column_names)
739
- null_scope? ? scope.pluck(*column_names) : super
740
- end
749
+ #
750
+ # Passing a block will select all of a person's pets in SQL and then
751
+ # perform the count using Ruby.
752
+ #
753
+ # person.pets.count { |pet| pet.name.include?('-') } # => 2
741
754
 
742
755
  # Returns the size of the collection. If the collection hasn't been loaded,
743
756
  # it executes a <tt>SELECT COUNT(*)</tt> query. Else it calls <tt>collection.size</tt>.
@@ -767,6 +780,12 @@ module ActiveRecord
767
780
  @association.size
768
781
  end
769
782
 
783
+ ##
784
+ # :method: length
785
+ #
786
+ # :call-seq:
787
+ # length()
788
+ #
770
789
  # Returns the size of the collection calling +size+ on the target.
771
790
  # If the collection has been already loaded, +length+ and +size+ are
772
791
  # equivalent. If not and you are going to need the records anyway this
@@ -787,9 +806,6 @@ module ActiveRecord
787
806
  # # #<Pet id: 2, name: "Spook", person_id: 1>,
788
807
  # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
789
808
  # # ]
790
- def length
791
- @association.length
792
- end
793
809
 
794
810
  # Returns +true+ if the collection is empty. If the collection has been
795
811
  # loaded it is equivalent
@@ -813,6 +829,12 @@ module ActiveRecord
813
829
  @association.empty?
814
830
  end
815
831
 
832
+ ##
833
+ # :method: any?
834
+ #
835
+ # :call-seq:
836
+ # any?()
837
+ #
816
838
  # Returns +true+ if the collection is not empty.
817
839
  #
818
840
  # class Person < ActiveRecord::Base
@@ -842,10 +864,13 @@ module ActiveRecord
842
864
  # pet.group == 'dogs'
843
865
  # end
844
866
  # # => true
845
- def any?(&block)
846
- @association.any?(&block)
847
- end
848
867
 
868
+ ##
869
+ # :method: many?
870
+ #
871
+ # :call-seq:
872
+ # many?()
873
+ #
849
874
  # Returns true if the collection has more than one record.
850
875
  # Equivalent to <tt>collection.size > 1</tt>.
851
876
  #
@@ -880,9 +905,6 @@ module ActiveRecord
880
905
  # pet.group == 'cats'
881
906
  # end
882
907
  # # => true
883
- def many?(&block)
884
- @association.many?(&block)
885
- end
886
908
 
887
909
  # Returns +true+ if the given +record+ is present in the collection.
888
910
  #
@@ -935,6 +957,12 @@ module ActiveRecord
935
957
  load_target == other
936
958
  end
937
959
 
960
+ ##
961
+ # :method: to_ary
962
+ #
963
+ # :call-seq:
964
+ # to_ary()
965
+ #
938
966
  # Returns a new array of objects from the collection. If the collection
939
967
  # hasn't been loaded, it fetches the records from the database.
940
968
  #
@@ -968,18 +996,15 @@ module ActiveRecord
968
996
  # # #<Pet id: 5, name: "Brain", person_id: 1>,
969
997
  # # #<Pet id: 6, name: "Boss", person_id: 1>
970
998
  # # ]
971
- def to_ary
972
- load_target.dup
973
- end
974
- alias_method :to_a, :to_ary
975
999
 
976
1000
  def records # :nodoc:
977
1001
  load_target
978
1002
  end
979
1003
 
980
1004
  # Adds one or more +records+ to the collection by setting their foreign keys
981
- # to the association's primary key. Returns +self+, so several appends may be
982
- # chained together.
1005
+ # to the association's primary key. Since <tt><<</tt> flattens its argument list and
1006
+ # inserts each record, +push+ and +concat+ behave identically. Returns +self+
1007
+ # so several appends may be chained together.
983
1008
  #
984
1009
  # class Person < ActiveRecord::Base
985
1010
  # has_many :pets
@@ -1002,8 +1027,9 @@ module ActiveRecord
1002
1027
  end
1003
1028
  alias_method :push, :<<
1004
1029
  alias_method :append, :<<
1030
+ alias_method :concat, :<<
1005
1031
 
1006
- def prepend(*args)
1032
+ def prepend(*args) # :nodoc:
1007
1033
  raise NoMethodError, "prepend on association is not defined. Please use <<, push or append"
1008
1034
  end
1009
1035
 
@@ -1019,7 +1045,6 @@ module ActiveRecord
1019
1045
  end
1020
1046
 
1021
1047
  # Reloads the collection from the database. Returns +self+.
1022
- # Equivalent to <tt>collection(true)</tt>.
1023
1048
  #
1024
1049
  # class Person < ActiveRecord::Base
1025
1050
  # has_many :pets
@@ -1033,11 +1058,8 @@ module ActiveRecord
1033
1058
  #
1034
1059
  # person.pets.reload # fetches pets from the database
1035
1060
  # # => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
1036
- #
1037
- # person.pets(true) # fetches pets from the database
1038
- # # => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
1039
1061
  def reload
1040
- proxy_association.reload
1062
+ proxy_association.reload(true)
1041
1063
  reset_scope
1042
1064
  end
1043
1065
 
@@ -1064,6 +1086,7 @@ module ActiveRecord
1064
1086
  end
1065
1087
 
1066
1088
  def reset_scope # :nodoc:
1089
+ @offsets = {}
1067
1090
  @scope = nil
1068
1091
  self
1069
1092
  end
@@ -1073,16 +1096,30 @@ module ActiveRecord
1073
1096
  SpawnMethods,
1074
1097
  ].flat_map { |klass|
1075
1098
  klass.public_instance_methods(false)
1076
- } - self.public_instance_methods(false) + [:scoping]
1099
+ } - self.public_instance_methods(false) - [:select] + [:scoping, :values]
1077
1100
 
1078
1101
  delegate(*delegate_methods, to: :scope)
1079
1102
 
1080
1103
  private
1081
1104
 
1105
+ def find_nth_with_limit(index, limit)
1106
+ load_target if find_from_target?
1107
+ super
1108
+ end
1109
+
1110
+ def find_nth_from_last(index)
1111
+ load_target if find_from_target?
1112
+ super
1113
+ end
1114
+
1082
1115
  def null_scope?
1083
1116
  @association.null_scope?
1084
1117
  end
1085
1118
 
1119
+ def find_from_target?
1120
+ @association.find_from_target?
1121
+ end
1122
+
1086
1123
  def exec_queries
1087
1124
  load_target
1088
1125
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord::Associations
2
4
  module ForeignAssociation # :nodoc:
3
5
  def foreign_key_present?
@@ -7,5 +9,12 @@ module ActiveRecord::Associations
7
9
  false
8
10
  end
9
11
  end
12
+
13
+ def nullified_owner_attributes
14
+ Hash.new.tap do |attrs|
15
+ attrs[reflection.foreign_key] = nil
16
+ attrs[reflection.type] = nil if reflection.type.present?
17
+ end
18
+ end
10
19
  end
11
20
  end
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
- # = Active Record Has Many Association
3
4
  module Associations
5
+ # = Active Record Has Many Association
4
6
  # This is the proxy that handles a has many association.
5
7
  #
6
8
  # If the association has a <tt>:through</tt> option further specialization
@@ -16,25 +18,16 @@ module ActiveRecord
16
18
  when :restrict_with_error
17
19
  unless empty?
18
20
  record = owner.class.human_attribute_name(reflection.name).downcase
19
- message = owner.errors.generate_message(:base, :'restrict_dependent_destroy.many', record: record, raise: true) rescue nil
20
- if message
21
- ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
22
- The error key `:'restrict_dependent_destroy.many'` has been deprecated and will be removed in Rails 5.1.
23
- Please use `:'restrict_dependent_destroy.has_many'` instead.
24
- MESSAGE
25
- end
26
- owner.errors.add(:base, message || :'restrict_dependent_destroy.has_many', record: record)
21
+ owner.errors.add(:base, :'restrict_dependent_destroy.has_many', record: record)
27
22
  throw(:abort)
28
23
  end
29
24
 
25
+ when :destroy
26
+ # No point in executing the counter update since we're going to destroy the parent anyway
27
+ load_target.each { |t| t.destroyed_by_association = reflection }
28
+ destroy_all
30
29
  else
31
- if options[:dependent] == :destroy
32
- # No point in executing the counter update since we're going to destroy the parent anyway
33
- load_target.each { |t| t.destroyed_by_association = reflection }
34
- destroy_all
35
- else
36
- delete_all
37
- end
30
+ delete_all
38
31
  end
39
32
  end
40
33
 
@@ -43,14 +36,6 @@ module ActiveRecord
43
36
  super
44
37
  end
45
38
 
46
- def empty?
47
- if reflection.has_cached_counter?
48
- size.zero?
49
- else
50
- super
51
- end
52
- end
53
-
54
39
  private
55
40
 
56
41
  # Returns the number of records in this collection.
@@ -68,15 +53,15 @@ module ActiveRecord
68
53
  # the loaded flag is set to true as well.
69
54
  def count_records
70
55
  count = if reflection.has_cached_counter?
71
- owner._read_attribute reflection.counter_cache_column
56
+ owner._read_attribute(reflection.counter_cache_column).to_i
72
57
  else
73
- scope.count
58
+ scope.count(:all)
74
59
  end
75
60
 
76
61
  # If there's nothing in the database and @target has no new records
77
62
  # we are certain the current target is an empty array. This is a
78
63
  # documented side-effect of the method that may avoid an extra SELECT.
79
- @target ||= [] and loaded! if count == 0
64
+ loaded! if count == 0
80
65
 
81
66
  [association_scope.limit_value, count].compact.min
82
67
  end
@@ -99,13 +84,14 @@ module ActiveRecord
99
84
  if method == :delete_all
100
85
  scope.delete_all
101
86
  else
102
- scope.update_all(reflection.foreign_key => nil)
87
+ scope.update_all(nullified_owner_attributes)
103
88
  end
104
89
  end
105
90
 
106
91
  def delete_or_nullify_all_records(method)
107
- count = delete_count(method, self.scope)
92
+ count = delete_count(method, scope)
108
93
  update_counter(-count)
94
+ count
109
95
  end
110
96
 
111
97
  # Deletes the records according to the <tt>:dependent</tt> option.
@@ -137,6 +123,14 @@ module ActiveRecord
137
123
  end
138
124
  saved_successfully
139
125
  end
126
+
127
+ def difference(a, b)
128
+ a - b
129
+ end
130
+
131
+ def intersection(a, b)
132
+ a & b
133
+ end
140
134
  end
141
135
  end
142
136
  end