activerecord 3.2.6 → 6.0.0

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 (371) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +611 -6417
  3. data/MIT-LICENSE +4 -2
  4. data/README.rdoc +44 -47
  5. data/examples/performance.rb +79 -71
  6. data/examples/simple.rb +6 -5
  7. data/lib/active_record/aggregations.rb +268 -238
  8. data/lib/active_record/association_relation.rb +40 -0
  9. data/lib/active_record/associations/alias_tracker.rb +47 -42
  10. data/lib/active_record/associations/association.rb +173 -81
  11. data/lib/active_record/associations/association_scope.rb +124 -92
  12. data/lib/active_record/associations/belongs_to_association.rb +83 -38
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +11 -9
  14. data/lib/active_record/associations/builder/association.rb +113 -32
  15. data/lib/active_record/associations/builder/belongs_to.rb +105 -60
  16. data/lib/active_record/associations/builder/collection_association.rb +53 -56
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +98 -41
  18. data/lib/active_record/associations/builder/has_many.rb +11 -63
  19. data/lib/active_record/associations/builder/has_one.rb +47 -45
  20. data/lib/active_record/associations/builder/singular_association.rb +30 -18
  21. data/lib/active_record/associations/collection_association.rb +217 -295
  22. data/lib/active_record/associations/collection_proxy.rb +1074 -77
  23. data/lib/active_record/associations/foreign_association.rb +20 -0
  24. data/lib/active_record/associations/has_many_association.rb +78 -50
  25. data/lib/active_record/associations/has_many_through_association.rb +99 -61
  26. data/lib/active_record/associations/has_one_association.rb +75 -30
  27. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  28. data/lib/active_record/associations/join_dependency/join_association.rb +45 -119
  29. data/lib/active_record/associations/join_dependency/join_base.rb +11 -12
  30. data/lib/active_record/associations/join_dependency/join_part.rb +35 -42
  31. data/lib/active_record/associations/join_dependency.rb +208 -164
  32. data/lib/active_record/associations/preloader/association.rb +93 -87
  33. data/lib/active_record/associations/preloader/through_association.rb +87 -38
  34. data/lib/active_record/associations/preloader.rb +134 -110
  35. data/lib/active_record/associations/singular_association.rb +19 -24
  36. data/lib/active_record/associations/through_association.rb +61 -27
  37. data/lib/active_record/associations.rb +1766 -1505
  38. data/lib/active_record/attribute_assignment.rb +57 -193
  39. data/lib/active_record/attribute_decorators.rb +90 -0
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +58 -8
  41. data/lib/active_record/attribute_methods/dirty.rb +187 -67
  42. data/lib/active_record/attribute_methods/primary_key.rb +100 -78
  43. data/lib/active_record/attribute_methods/query.rb +10 -8
  44. data/lib/active_record/attribute_methods/read.rb +29 -118
  45. data/lib/active_record/attribute_methods/serialization.rb +60 -72
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +69 -42
  47. data/lib/active_record/attribute_methods/write.rb +36 -44
  48. data/lib/active_record/attribute_methods.rb +306 -161
  49. data/lib/active_record/attributes.rb +279 -0
  50. data/lib/active_record/autosave_association.rb +324 -238
  51. data/lib/active_record/base.rb +114 -507
  52. data/lib/active_record/callbacks.rb +147 -83
  53. data/lib/active_record/coders/json.rb +15 -0
  54. data/lib/active_record/coders/yaml_column.rb +32 -23
  55. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +962 -279
  56. data/lib/active_record/connection_adapters/abstract/database_limits.rb +32 -5
  57. data/lib/active_record/connection_adapters/abstract/database_statements.rb +331 -209
  58. data/lib/active_record/connection_adapters/abstract/query_cache.rb +95 -23
  59. data/lib/active_record/connection_adapters/abstract/quoting.rb +201 -65
  60. data/lib/active_record/connection_adapters/abstract/savepoints.rb +23 -0
  61. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +510 -289
  63. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +93 -0
  64. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1182 -313
  65. data/lib/active_record/connection_adapters/abstract/transaction.rb +323 -0
  66. data/lib/active_record/connection_adapters/abstract_adapter.rb +585 -120
  67. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +610 -463
  68. data/lib/active_record/connection_adapters/column.rb +58 -233
  69. data/lib/active_record/connection_adapters/connection_specification.rb +297 -0
  70. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +29 -0
  71. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  72. data/lib/active_record/connection_adapters/mysql/database_statements.rb +200 -0
  73. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  74. data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +72 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +95 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +88 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
  79. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +31 -0
  80. data/lib/active_record/connection_adapters/mysql2_adapter.rb +75 -207
  81. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -0
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +182 -0
  83. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +92 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +53 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +50 -0
  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 +23 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +21 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +71 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
  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 +41 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +65 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +97 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +113 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid.rb +34 -0
  107. data/lib/active_record/connection_adapters/postgresql/quoting.rb +205 -0
  108. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +43 -0
  109. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +222 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +776 -0
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +81 -0
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +695 -1052
  116. data/lib/active_record/connection_adapters/schema_cache.rb +115 -24
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +37 -0
  118. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +103 -0
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  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 +528 -26
  126. data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
  127. data/lib/active_record/connection_handling.rb +267 -0
  128. data/lib/active_record/core.rb +599 -0
  129. data/lib/active_record/counter_cache.rb +177 -103
  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 +107 -64
  136. data/lib/active_record/enum.rb +274 -0
  137. data/lib/active_record/errors.rb +254 -61
  138. data/lib/active_record/explain.rb +35 -70
  139. data/lib/active_record/explain_registry.rb +32 -0
  140. data/lib/active_record/explain_subscriber.rb +18 -8
  141. data/lib/active_record/fixture_set/file.rb +82 -0
  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 +291 -475
  147. data/lib/active_record/gem_version.rb +17 -0
  148. data/lib/active_record/inheritance.rb +219 -100
  149. data/lib/active_record/insert_all.rb +179 -0
  150. data/lib/active_record/integration.rb +175 -17
  151. data/lib/active_record/internal_metadata.rb +53 -0
  152. data/lib/active_record/legacy_yaml_adapter.rb +48 -0
  153. data/lib/active_record/locale/en.yml +9 -1
  154. data/lib/active_record/locking/optimistic.rb +106 -92
  155. data/lib/active_record/locking/pessimistic.rb +23 -11
  156. data/lib/active_record/log_subscriber.rb +80 -30
  157. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  158. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  159. data/lib/active_record/middleware/database_selector.rb +75 -0
  160. data/lib/active_record/migration/command_recorder.rb +235 -56
  161. data/lib/active_record/migration/compatibility.rb +244 -0
  162. data/lib/active_record/migration/join_table.rb +17 -0
  163. data/lib/active_record/migration.rb +917 -301
  164. data/lib/active_record/model_schema.rb +351 -175
  165. data/lib/active_record/nested_attributes.rb +366 -235
  166. data/lib/active_record/no_touching.rb +65 -0
  167. data/lib/active_record/null_relation.rb +68 -0
  168. data/lib/active_record/persistence.rb +761 -166
  169. data/lib/active_record/query_cache.rb +22 -44
  170. data/lib/active_record/querying.rb +55 -31
  171. data/lib/active_record/railtie.rb +185 -47
  172. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  173. data/lib/active_record/railties/console_sandbox.rb +5 -4
  174. data/lib/active_record/railties/controller_runtime.rb +35 -33
  175. data/lib/active_record/railties/databases.rake +366 -463
  176. data/lib/active_record/readonly_attributes.rb +4 -6
  177. data/lib/active_record/reflection.rb +736 -228
  178. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  179. data/lib/active_record/relation/batches.rb +252 -52
  180. data/lib/active_record/relation/calculations.rb +340 -270
  181. data/lib/active_record/relation/delegation.rb +117 -36
  182. data/lib/active_record/relation/finder_methods.rb +439 -286
  183. data/lib/active_record/relation/from_clause.rb +26 -0
  184. data/lib/active_record/relation/merger.rb +184 -0
  185. data/lib/active_record/relation/predicate_builder/array_handler.rb +49 -0
  186. data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
  187. data/lib/active_record/relation/predicate_builder/base_handler.rb +18 -0
  188. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  189. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
  190. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  191. data/lib/active_record/relation/predicate_builder/relation_handler.rb +19 -0
  192. data/lib/active_record/relation/predicate_builder.rb +131 -39
  193. data/lib/active_record/relation/query_attribute.rb +50 -0
  194. data/lib/active_record/relation/query_methods.rb +1163 -221
  195. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  196. data/lib/active_record/relation/spawn_methods.rb +49 -120
  197. data/lib/active_record/relation/where_clause.rb +190 -0
  198. data/lib/active_record/relation/where_clause_factory.rb +33 -0
  199. data/lib/active_record/relation.rb +671 -349
  200. data/lib/active_record/result.rb +149 -15
  201. data/lib/active_record/runtime_registry.rb +24 -0
  202. data/lib/active_record/sanitization.rb +153 -133
  203. data/lib/active_record/schema.rb +22 -19
  204. data/lib/active_record/schema_dumper.rb +178 -112
  205. data/lib/active_record/schema_migration.rb +60 -0
  206. data/lib/active_record/scoping/default.rb +107 -98
  207. data/lib/active_record/scoping/named.rb +130 -115
  208. data/lib/active_record/scoping.rb +77 -123
  209. data/lib/active_record/secure_token.rb +40 -0
  210. data/lib/active_record/serialization.rb +10 -6
  211. data/lib/active_record/statement_cache.rb +148 -0
  212. data/lib/active_record/store.rb +256 -16
  213. data/lib/active_record/suppressor.rb +61 -0
  214. data/lib/active_record/table_metadata.rb +75 -0
  215. data/lib/active_record/tasks/database_tasks.rb +506 -0
  216. data/lib/active_record/tasks/mysql_database_tasks.rb +115 -0
  217. data/lib/active_record/tasks/postgresql_database_tasks.rb +141 -0
  218. data/lib/active_record/tasks/sqlite_database_tasks.rb +77 -0
  219. data/lib/active_record/test_databases.rb +23 -0
  220. data/lib/active_record/test_fixtures.rb +224 -0
  221. data/lib/active_record/timestamp.rb +93 -39
  222. data/lib/active_record/touch_later.rb +66 -0
  223. data/lib/active_record/transactions.rb +260 -129
  224. data/lib/active_record/translation.rb +3 -1
  225. data/lib/active_record/type/adapter_specific_registry.rb +129 -0
  226. data/lib/active_record/type/date.rb +9 -0
  227. data/lib/active_record/type/date_time.rb +9 -0
  228. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  229. data/lib/active_record/type/hash_lookup_type_map.rb +25 -0
  230. data/lib/active_record/type/internal/timezone.rb +17 -0
  231. data/lib/active_record/type/json.rb +30 -0
  232. data/lib/active_record/type/serialized.rb +71 -0
  233. data/lib/active_record/type/text.rb +11 -0
  234. data/lib/active_record/type/time.rb +21 -0
  235. data/lib/active_record/type/type_map.rb +62 -0
  236. data/lib/active_record/type/unsigned_integer.rb +17 -0
  237. data/lib/active_record/type.rb +78 -0
  238. data/lib/active_record/type_caster/connection.rb +34 -0
  239. data/lib/active_record/type_caster/map.rb +20 -0
  240. data/lib/active_record/type_caster.rb +9 -0
  241. data/lib/active_record/validations/absence.rb +25 -0
  242. data/lib/active_record/validations/associated.rb +35 -18
  243. data/lib/active_record/validations/length.rb +26 -0
  244. data/lib/active_record/validations/presence.rb +68 -0
  245. data/lib/active_record/validations/uniqueness.rb +123 -77
  246. data/lib/active_record/validations.rb +54 -43
  247. data/lib/active_record/version.rb +7 -7
  248. data/lib/active_record.rb +97 -49
  249. data/lib/arel/alias_predication.rb +9 -0
  250. data/lib/arel/attributes/attribute.rb +37 -0
  251. data/lib/arel/attributes.rb +22 -0
  252. data/lib/arel/collectors/bind.rb +24 -0
  253. data/lib/arel/collectors/composite.rb +31 -0
  254. data/lib/arel/collectors/plain_string.rb +20 -0
  255. data/lib/arel/collectors/sql_string.rb +20 -0
  256. data/lib/arel/collectors/substitute_binds.rb +28 -0
  257. data/lib/arel/crud.rb +42 -0
  258. data/lib/arel/delete_manager.rb +18 -0
  259. data/lib/arel/errors.rb +9 -0
  260. data/lib/arel/expressions.rb +29 -0
  261. data/lib/arel/factory_methods.rb +49 -0
  262. data/lib/arel/insert_manager.rb +49 -0
  263. data/lib/arel/math.rb +45 -0
  264. data/lib/arel/nodes/and.rb +32 -0
  265. data/lib/arel/nodes/ascending.rb +23 -0
  266. data/lib/arel/nodes/binary.rb +52 -0
  267. data/lib/arel/nodes/bind_param.rb +36 -0
  268. data/lib/arel/nodes/case.rb +55 -0
  269. data/lib/arel/nodes/casted.rb +50 -0
  270. data/lib/arel/nodes/comment.rb +29 -0
  271. data/lib/arel/nodes/count.rb +12 -0
  272. data/lib/arel/nodes/delete_statement.rb +45 -0
  273. data/lib/arel/nodes/descending.rb +23 -0
  274. data/lib/arel/nodes/equality.rb +18 -0
  275. data/lib/arel/nodes/extract.rb +24 -0
  276. data/lib/arel/nodes/false.rb +16 -0
  277. data/lib/arel/nodes/full_outer_join.rb +8 -0
  278. data/lib/arel/nodes/function.rb +44 -0
  279. data/lib/arel/nodes/grouping.rb +8 -0
  280. data/lib/arel/nodes/in.rb +8 -0
  281. data/lib/arel/nodes/infix_operation.rb +80 -0
  282. data/lib/arel/nodes/inner_join.rb +8 -0
  283. data/lib/arel/nodes/insert_statement.rb +37 -0
  284. data/lib/arel/nodes/join_source.rb +20 -0
  285. data/lib/arel/nodes/matches.rb +18 -0
  286. data/lib/arel/nodes/named_function.rb +23 -0
  287. data/lib/arel/nodes/node.rb +50 -0
  288. data/lib/arel/nodes/node_expression.rb +13 -0
  289. data/lib/arel/nodes/outer_join.rb +8 -0
  290. data/lib/arel/nodes/over.rb +15 -0
  291. data/lib/arel/nodes/regexp.rb +16 -0
  292. data/lib/arel/nodes/right_outer_join.rb +8 -0
  293. data/lib/arel/nodes/select_core.rb +67 -0
  294. data/lib/arel/nodes/select_statement.rb +41 -0
  295. data/lib/arel/nodes/sql_literal.rb +16 -0
  296. data/lib/arel/nodes/string_join.rb +11 -0
  297. data/lib/arel/nodes/table_alias.rb +27 -0
  298. data/lib/arel/nodes/terminal.rb +16 -0
  299. data/lib/arel/nodes/true.rb +16 -0
  300. data/lib/arel/nodes/unary.rb +45 -0
  301. data/lib/arel/nodes/unary_operation.rb +20 -0
  302. data/lib/arel/nodes/unqualified_column.rb +22 -0
  303. data/lib/arel/nodes/update_statement.rb +41 -0
  304. data/lib/arel/nodes/values_list.rb +9 -0
  305. data/lib/arel/nodes/window.rb +126 -0
  306. data/lib/arel/nodes/with.rb +11 -0
  307. data/lib/arel/nodes.rb +68 -0
  308. data/lib/arel/order_predications.rb +13 -0
  309. data/lib/arel/predications.rb +257 -0
  310. data/lib/arel/select_manager.rb +271 -0
  311. data/lib/arel/table.rb +110 -0
  312. data/lib/arel/tree_manager.rb +72 -0
  313. data/lib/arel/update_manager.rb +34 -0
  314. data/lib/arel/visitors/depth_first.rb +204 -0
  315. data/lib/arel/visitors/dot.rb +297 -0
  316. data/lib/arel/visitors/ibm_db.rb +34 -0
  317. data/lib/arel/visitors/informix.rb +62 -0
  318. data/lib/arel/visitors/mssql.rb +157 -0
  319. data/lib/arel/visitors/mysql.rb +83 -0
  320. data/lib/arel/visitors/oracle.rb +159 -0
  321. data/lib/arel/visitors/oracle12.rb +66 -0
  322. data/lib/arel/visitors/postgresql.rb +110 -0
  323. data/lib/arel/visitors/sqlite.rb +39 -0
  324. data/lib/arel/visitors/to_sql.rb +889 -0
  325. data/lib/arel/visitors/visitor.rb +46 -0
  326. data/lib/arel/visitors/where_sql.rb +23 -0
  327. data/lib/arel/visitors.rb +20 -0
  328. data/lib/arel/window_predications.rb +9 -0
  329. data/lib/arel.rb +51 -0
  330. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  331. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  332. data/lib/rails/generators/active_record/migration/migration_generator.rb +59 -9
  333. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
  334. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +48 -0
  335. data/lib/rails/generators/active_record/migration.rb +41 -8
  336. data/lib/rails/generators/active_record/model/model_generator.rb +24 -22
  337. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  338. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +1 -1
  339. data/lib/rails/generators/active_record.rb +10 -16
  340. metadata +285 -149
  341. data/examples/associations.png +0 -0
  342. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
  343. data/lib/active_record/associations/join_helper.rb +0 -55
  344. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  345. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  346. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  347. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  348. data/lib/active_record/associations/preloader/has_many_through.rb +0 -15
  349. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  350. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  351. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  352. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  353. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -188
  354. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -426
  355. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -579
  356. data/lib/active_record/dynamic_finder_match.rb +0 -68
  357. data/lib/active_record/dynamic_scope_match.rb +0 -23
  358. data/lib/active_record/fixtures/file.rb +0 -65
  359. data/lib/active_record/identity_map.rb +0 -162
  360. data/lib/active_record/observer.rb +0 -121
  361. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  362. data/lib/active_record/serializers/xml_serializer.rb +0 -203
  363. data/lib/active_record/session_store.rb +0 -358
  364. data/lib/active_record/test_case.rb +0 -73
  365. data/lib/rails/generators/active_record/migration/templates/migration.rb +0 -34
  366. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
  367. data/lib/rails/generators/active_record/model/templates/model.rb +0 -12
  368. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  369. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  370. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  371. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord::Associations
4
+ module ForeignAssociation # :nodoc:
5
+ def foreign_key_present?
6
+ if reflection.klass.primary_key
7
+ owner.attribute_present?(reflection.active_record_primary_key)
8
+ else
9
+ false
10
+ end
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
19
+ end
20
+ end
@@ -1,22 +1,41 @@
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
7
9
  # is provided by its child HasManyThroughAssociation.
8
10
  class HasManyAssociation < CollectionAssociation #:nodoc:
11
+ include ForeignAssociation
9
12
 
10
- def insert_record(record, validate = true, raise = false)
11
- set_owner_attributes(record)
13
+ def handle_dependency
14
+ case options[:dependent]
15
+ when :restrict_with_exception
16
+ raise ActiveRecord::DeleteRestrictionError.new(reflection.name) unless empty?
12
17
 
13
- if raise
14
- record.save!(:validate => validate)
18
+ when :restrict_with_error
19
+ unless empty?
20
+ record = owner.class.human_attribute_name(reflection.name).downcase
21
+ owner.errors.add(:base, :'restrict_dependent_destroy.has_many', record: record)
22
+ throw(:abort)
23
+ end
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
15
29
  else
16
- record.save(:validate => validate)
30
+ delete_all
17
31
  end
18
32
  end
19
33
 
34
+ def insert_record(record, validate = true, raise = false)
35
+ set_owner_attributes(record)
36
+ super
37
+ end
38
+
20
39
  private
21
40
 
22
41
  # Returns the number of records in this collection.
@@ -33,75 +52,84 @@ module ActiveRecord
33
52
  # If the collection is empty the target is set to an empty array and
34
53
  # the loaded flag is set to true as well.
35
54
  def count_records
36
- count = if has_cached_counter?
37
- owner.send(:read_attribute, cached_counter_attribute_name)
38
- elsif options[:counter_sql] || options[:finder_sql]
39
- reflection.klass.count_by_sql(custom_counter_sql)
55
+ count = if reflection.has_cached_counter?
56
+ owner._read_attribute(reflection.counter_cache_column).to_i
40
57
  else
41
- scoped.count
58
+ scope.count(:all)
42
59
  end
43
60
 
44
61
  # If there's nothing in the database and @target has no new records
45
62
  # we are certain the current target is an empty array. This is a
46
63
  # documented side-effect of the method that may avoid an extra SELECT.
47
- @target ||= [] and loaded! if count == 0
64
+ loaded! if count == 0
48
65
 
49
- [options[:limit], count].compact.min
66
+ [association_scope.limit_value, count].compact.min
50
67
  end
51
68
 
52
- def has_cached_counter?(reflection = reflection)
53
- owner.attribute_present?(cached_counter_attribute_name(reflection))
69
+ def update_counter(difference, reflection = reflection())
70
+ if reflection.has_cached_counter?
71
+ owner.increment!(reflection.counter_cache_column, difference)
72
+ end
54
73
  end
55
74
 
56
- def cached_counter_attribute_name(reflection = reflection)
57
- "#{reflection.name}_count"
75
+ def update_counter_in_memory(difference, reflection = reflection())
76
+ if reflection.counter_must_be_updated_by_has_many?
77
+ counter = reflection.counter_cache_column
78
+ owner.increment(counter, difference)
79
+ owner.send(:clear_attribute_change, counter) # eww
80
+ end
58
81
  end
59
82
 
60
- def update_counter(difference, reflection = reflection)
61
- if has_cached_counter?(reflection)
62
- counter = cached_counter_attribute_name(reflection)
63
- owner.class.update_counters(owner.id, counter => difference)
64
- owner[counter] += difference
65
- owner.changed_attributes.delete(counter) # eww
83
+ def delete_count(method, scope)
84
+ if method == :delete_all
85
+ scope.delete_all
86
+ else
87
+ scope.update_all(nullified_owner_attributes)
66
88
  end
67
89
  end
68
90
 
69
- # This shit is nasty. We need to avoid the following situation:
70
- #
71
- # * An associated record is deleted via record.destroy
72
- # * Hence the callbacks run, and they find a belongs_to on the record with a
73
- # :counter_cache options which points back at our owner. So they update the
74
- # counter cache.
75
- # * In which case, we must make sure to *not* update the counter cache, or else
76
- # it will be decremented twice.
77
- #
78
- # Hence this method.
79
- def inverse_updates_counter_cache?(reflection = reflection)
80
- counter_name = cached_counter_attribute_name(reflection)
81
- reflection.klass.reflect_on_all_associations(:belongs_to).any? { |inverse_reflection|
82
- inverse_reflection.counter_cache_column == counter_name
83
- }
91
+ def delete_or_nullify_all_records(method)
92
+ count = delete_count(method, scope)
93
+ update_counter(-count)
94
+ count
84
95
  end
85
96
 
86
97
  # Deletes the records according to the <tt>:dependent</tt> option.
87
98
  def delete_records(records, method)
88
99
  if method == :destroy
89
- records.each { |r| r.destroy }
90
- update_counter(-records.length) unless inverse_updates_counter_cache?
100
+ records.each(&:destroy!)
101
+ update_counter(-records.length) unless reflection.inverse_updates_counter_cache?
102
+ else
103
+ scope = self.scope.where(reflection.klass.primary_key => records)
104
+ update_counter(-delete_count(method, scope))
105
+ end
106
+ end
107
+
108
+ def concat_records(records, *)
109
+ update_counter_if_success(super, records.length)
110
+ end
111
+
112
+ def _create_record(attributes, *)
113
+ if attributes.is_a?(Array)
114
+ super
91
115
  else
92
- keys = records.map { |r| r[reflection.association_primary_key] }
93
- scope = scoped.where(reflection.association_primary_key => keys)
94
-
95
- if method == :delete_all
96
- update_counter(-scope.delete_all)
97
- else
98
- update_counter(-scope.update_all(reflection.foreign_key => nil))
99
- end
116
+ update_counter_if_success(super, 1)
117
+ end
118
+ end
119
+
120
+ def update_counter_if_success(saved_successfully, difference)
121
+ if saved_successfully
122
+ update_counter_in_memory(difference)
100
123
  end
124
+ saved_successfully
125
+ end
126
+
127
+ def difference(a, b)
128
+ a - b
101
129
  end
102
130
 
103
- def foreign_key_present?
104
- owner.attribute_present?(reflection.association_primary_key)
131
+ def intersection(a, b)
132
+ a & b
105
133
  end
106
134
  end
107
135
  end
@@ -1,37 +1,20 @@
1
- require 'active_support/core_ext/object/blank'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecord
4
- # = Active Record Has Many Through Association
5
4
  module Associations
5
+ # = Active Record Has Many Through Association
6
6
  class HasManyThroughAssociation < HasManyAssociation #:nodoc:
7
7
  include ThroughAssociation
8
8
 
9
9
  def initialize(owner, reflection)
10
10
  super
11
-
12
- @through_records = {}
13
- @through_association = nil
14
- end
15
-
16
- # Returns the size of the collection by executing a SELECT COUNT(*) query if the collection hasn't been
17
- # loaded and calling collection.size if it has. If it's more likely than not that the collection does
18
- # have a size larger than zero, and you need to fetch that collection afterwards, it'll take one fewer
19
- # SELECT query if you use #length.
20
- def size
21
- if has_cached_counter?
22
- owner.send(:read_attribute, cached_counter_attribute_name)
23
- elsif loaded?
24
- target.size
25
- else
26
- count
27
- end
11
+ @through_records = {}
28
12
  end
29
13
 
30
14
  def concat(*records)
31
15
  unless owner.new_record?
32
16
  records.flatten.each do |record|
33
- raise_on_type_mismatch(record)
34
- record.save! if record.new_record?
17
+ raise_on_type_mismatch!(record)
35
18
  end
36
19
  end
37
20
 
@@ -41,62 +24,72 @@ module ActiveRecord
41
24
  def insert_record(record, validate = true, raise = false)
42
25
  ensure_not_nested
43
26
 
44
- if record.new_record?
45
- if raise
46
- record.save!(:validate => validate)
47
- else
48
- return unless record.save(:validate => validate)
49
- end
27
+ if record.new_record? || record.has_changes_to_save?
28
+ return unless super
50
29
  end
51
30
 
52
31
  save_through_record(record)
53
- update_counter(1)
32
+
54
33
  record
55
34
  end
56
35
 
57
- # ActiveRecord::Relation#delete_all needs to support joins before we can use a
58
- # SQL-only implementation.
59
- alias delete_all_on_destroy delete_all
60
-
61
36
  private
37
+ def concat_records(records)
38
+ ensure_not_nested
39
+
40
+ records = super(records, true)
62
41
 
63
- def through_association
64
- @through_association ||= owner.association(through_reflection.name)
42
+ if owner.new_record? && records
43
+ records.flatten.each do |record|
44
+ build_through_record(record)
45
+ end
46
+ end
47
+
48
+ records
65
49
  end
66
50
 
67
- # We temporarily cache through record that has been build, because if we build a
68
- # through record in build_record and then subsequently call insert_record, then we
69
- # want to use the exact same object.
51
+ # The through record (built with build_record) is temporarily cached
52
+ # so that it may be reused if insert_record is subsequently called.
70
53
  #
71
- # However, after insert_record has been called, we clear the cache entry because
72
- # we want it to be possible to have multiple instances of the same record in an
73
- # association
54
+ # However, after insert_record has been called, the cache is cleared in
55
+ # order to allow multiple instances of the same record in an association.
74
56
  def build_through_record(record)
75
57
  @through_records[record.object_id] ||= begin
76
58
  ensure_mutable
77
59
 
78
- through_record = through_association.build
79
- through_record.send("#{source_reflection.name}=", record)
80
- through_record
60
+ attributes = through_scope_attributes
61
+ attributes[source_reflection.name] = record
62
+ attributes[source_reflection.foreign_type] = options[:source_type] if options[:source_type]
63
+
64
+ through_association.build(attributes)
81
65
  end
82
66
  end
83
67
 
68
+ def through_scope_attributes
69
+ scope.where_values_hash(through_association.reflection.name.to_s).
70
+ except!(through_association.reflection.foreign_key,
71
+ through_association.reflection.klass.inheritance_column)
72
+ end
73
+
84
74
  def save_through_record(record)
85
- build_through_record(record).save!
75
+ association = build_through_record(record)
76
+ if association.changed?
77
+ association.save!
78
+ end
86
79
  ensure
87
80
  @through_records.delete(record.object_id)
88
81
  end
89
82
 
90
- def build_record(attributes, options = {})
83
+ def build_record(attributes)
91
84
  ensure_not_nested
92
85
 
93
- record = super(attributes, options)
86
+ record = super
94
87
 
95
88
  inverse = source_reflection.inverse_of
96
89
  if inverse
97
- if inverse.macro == :has_many
90
+ if inverse.collection?
98
91
  record.send(inverse.name) << build_through_record(record)
99
- elsif inverse.macro == :has_one
92
+ elsif inverse.has_one?
100
93
  record.send("#{inverse.name}=", build_through_record(record))
101
94
  end
102
95
  end
@@ -104,18 +97,19 @@ module ActiveRecord
104
97
  record
105
98
  end
106
99
 
100
+ def remove_records(existing_records, records, method)
101
+ super
102
+ delete_through_records(records)
103
+ end
104
+
107
105
  def target_reflection_has_associated_record?
108
- if through_reflection.macro == :belongs_to && owner[through_reflection.foreign_key].blank?
109
- false
110
- else
111
- true
112
- end
106
+ !(through_reflection.belongs_to? && owner[through_reflection.foreign_key].blank?)
113
107
  end
114
108
 
115
109
  def update_through_counter?(method)
116
110
  case method
117
111
  when :destroy
118
- !inverse_updates_counter_cache?(through_reflection)
112
+ !through_reflection.inverse_updates_counter_cache?
119
113
  when :nullify
120
114
  false
121
115
  else
@@ -123,14 +117,25 @@ module ActiveRecord
123
117
  end
124
118
  end
125
119
 
120
+ def delete_or_nullify_all_records(method)
121
+ delete_records(load_target, method)
122
+ end
123
+
126
124
  def delete_records(records, method)
127
125
  ensure_not_nested
128
126
 
129
- scope = through_association.scoped.where(construct_join_attributes(*records))
127
+ scope = through_association.scope
128
+ scope.where! construct_join_attributes(*records)
129
+ scope = scope.where(through_scope_attributes)
130
130
 
131
131
  case method
132
132
  when :destroy
133
- count = scope.destroy_all.length
133
+ if scope.klass.primary_key
134
+ count = scope.destroy_all.count(&:destroyed?)
135
+ else
136
+ scope.each(&:_run_destroy_callbacks)
137
+ count = scope.delete_all
138
+ end
134
139
  when :nullify
135
140
  count = scope.update_all(source_reflection.foreign_key => nil)
136
141
  else
@@ -139,24 +144,57 @@ module ActiveRecord
139
144
 
140
145
  delete_through_records(records)
141
146
 
142
- if through_reflection.macro == :has_many && update_through_counter?(method)
147
+ if source_reflection.options[:counter_cache] && method != :destroy
148
+ counter = source_reflection.counter_cache_column
149
+ klass.decrement_counter counter, records.map(&:id)
150
+ end
151
+
152
+ if through_reflection.collection? && update_through_counter?(method)
143
153
  update_counter(-count, through_reflection)
154
+ else
155
+ update_counter(-count)
144
156
  end
145
157
 
146
- update_counter(-count)
158
+ count
159
+ end
160
+
161
+ def difference(a, b)
162
+ distribution = distribution(b)
163
+
164
+ a.reject { |record| mark_occurrence(distribution, record) }
165
+ end
166
+
167
+ def intersection(a, b)
168
+ distribution = distribution(b)
169
+
170
+ a.select { |record| mark_occurrence(distribution, record) }
171
+ end
172
+
173
+ def mark_occurrence(distribution, record)
174
+ distribution[record] > 0 && distribution[record] -= 1
175
+ end
176
+
177
+ def distribution(array)
178
+ array.each_with_object(Hash.new(0)) do |record, distribution|
179
+ distribution[record] += 1
180
+ end
147
181
  end
148
182
 
149
183
  def through_records_for(record)
150
184
  attributes = construct_join_attributes(record)
151
185
  candidates = Array.wrap(through_association.target)
152
- candidates.find_all { |c| c.attributes.slice(*attributes.keys) == attributes }
186
+ candidates.find_all do |c|
187
+ attributes.all? do |key, value|
188
+ c.public_send(key) == value
189
+ end
190
+ end
153
191
  end
154
192
 
155
193
  def delete_through_records(records)
156
194
  records.each do |record|
157
195
  through_records = through_records_for(record)
158
196
 
159
- if through_reflection.macro == :has_many
197
+ if through_reflection.collection?
160
198
  through_records.each { |r| through_association.target.delete(r) }
161
199
  else
162
200
  if through_records.include?(through_association.target)
@@ -170,7 +208,7 @@ module ActiveRecord
170
208
 
171
209
  def find_target
172
210
  return [] unless target_reflection_has_associated_record?
173
- scoped.all
211
+ super
174
212
  end
175
213
 
176
214
  # NOTE - not sure that we can actually cope with inverses here
@@ -1,47 +1,71 @@
1
- require 'active_support/core_ext/object/inclusion'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecord
4
- # = Active Record Belongs To Has One Association
5
4
  module Associations
5
+ # = Active Record Has One Association
6
6
  class HasOneAssociation < SingularAssociation #:nodoc:
7
- def replace(record, save = true)
8
- raise_on_type_mismatch(record) if record
9
- load_target
7
+ include ForeignAssociation
10
8
 
11
- reflection.klass.transaction do
12
- if target && target != record
13
- remove_target!(options[:dependent]) unless target.destroyed?
14
- end
15
-
16
- if record
17
- set_owner_attributes(record)
18
- set_inverse_instance(record)
9
+ def handle_dependency
10
+ case options[:dependent]
11
+ when :restrict_with_exception
12
+ raise ActiveRecord::DeleteRestrictionError.new(reflection.name) if load_target
19
13
 
20
- if owner.persisted? && save && !record.save
21
- nullify_owner_attributes(record)
22
- set_owner_attributes(target) if target
23
- raise RecordNotSaved, "Failed to save the new associated #{reflection.name}."
24
- end
14
+ when :restrict_with_error
15
+ if load_target
16
+ record = owner.class.human_attribute_name(reflection.name).downcase
17
+ owner.errors.add(:base, :'restrict_dependent_destroy.has_one', record: record)
18
+ throw(:abort)
25
19
  end
26
- end
27
20
 
28
- self.target = record
21
+ else
22
+ delete
23
+ end
29
24
  end
30
25
 
31
26
  def delete(method = options[:dependent])
32
27
  if load_target
33
28
  case method
34
- when :delete
35
- target.delete
36
- when :destroy
37
- target.destroy
38
- when :nullify
39
- target.update_attribute(reflection.foreign_key, nil)
29
+ when :delete
30
+ target.delete
31
+ when :destroy
32
+ target.destroyed_by_association = reflection
33
+ target.destroy
34
+ throw(:abort) unless target.destroyed?
35
+ when :nullify
36
+ target.update_columns(nullified_owner_attributes) if target.persisted?
40
37
  end
41
38
  end
42
39
  end
43
40
 
44
41
  private
42
+ def replace(record, save = true)
43
+ raise_on_type_mismatch!(record) if record
44
+
45
+ return target unless load_target || record
46
+
47
+ assigning_another_record = target != record
48
+ if assigning_another_record || record.has_changes_to_save?
49
+ save &&= owner.persisted?
50
+
51
+ transaction_if(save) do
52
+ remove_target!(options[:dependent]) if target && !target.destroyed? && assigning_another_record
53
+
54
+ if record
55
+ set_owner_attributes(record)
56
+ set_inverse_instance(record)
57
+
58
+ if save && !record.save
59
+ nullify_owner_attributes(record)
60
+ set_owner_attributes(target) if target
61
+ raise RecordNotSaved, "Failed to save the new associated #{reflection.name}."
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ self.target = record
68
+ end
45
69
 
46
70
  # The reason that the save param for replace is false, if for create (not just build),
47
71
  # is because the setting of the foreign keys is actually handled by the scoping when
@@ -52,15 +76,20 @@ module ActiveRecord
52
76
  end
53
77
 
54
78
  def remove_target!(method)
55
- if method.in?([:delete, :destroy])
56
- target.send(method)
79
+ case method
80
+ when :delete
81
+ target.delete
82
+ when :destroy
83
+ target.destroyed_by_association = reflection
84
+ target.destroy
57
85
  else
58
86
  nullify_owner_attributes(target)
87
+ remove_inverse_instance(target)
59
88
 
60
89
  if target.persisted? && owner.persisted? && !target.save
61
90
  set_owner_attributes(target)
62
- raise RecordNotSaved, "Failed to remove the existing associated #{reflection.name}. " +
63
- "The record failed to save when after its foreign key was set to nil."
91
+ raise RecordNotSaved, "Failed to remove the existing associated #{reflection.name}. " \
92
+ "The record failed to save after its foreign key was set to nil."
64
93
  end
65
94
  end
66
95
  end
@@ -68,6 +97,22 @@ module ActiveRecord
68
97
  def nullify_owner_attributes(record)
69
98
  record[reflection.foreign_key] = nil
70
99
  end
100
+
101
+ def transaction_if(value)
102
+ if value
103
+ reflection.klass.transaction { yield }
104
+ else
105
+ yield
106
+ end
107
+ end
108
+
109
+ def _create_record(attributes, raise_error = false, &block)
110
+ unless owner.persisted?
111
+ raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved"
112
+ end
113
+
114
+ super
115
+ end
71
116
  end
72
117
  end
73
118
  end
@@ -1,30 +1,39 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
- # = Active Record Has One Through Association
3
4
  module Associations
5
+ # = Active Record Has One Through Association
4
6
  class HasOneThroughAssociation < HasOneAssociation #:nodoc:
5
7
  include ThroughAssociation
6
8
 
7
- def replace(record)
8
- create_through_record(record)
9
- self.target = record
10
- end
11
-
12
9
  private
10
+ def replace(record, save = true)
11
+ create_through_record(record, save)
12
+ self.target = record
13
+ end
13
14
 
14
- def create_through_record(record)
15
+ def create_through_record(record, save)
15
16
  ensure_not_nested
16
17
 
17
- through_proxy = owner.association(through_reflection.name)
18
- through_record = through_proxy.send(:load_target)
18
+ through_proxy = through_association
19
+ through_record = through_proxy.load_target
19
20
 
20
21
  if through_record && !record
21
22
  through_record.destroy
22
23
  elsif record
23
24
  attributes = construct_join_attributes(record)
24
25
 
26
+ if through_record && through_record.destroyed?
27
+ through_record = through_proxy.tap(&:reload).target
28
+ end
29
+
25
30
  if through_record
26
- through_record.update_attributes(attributes)
27
- elsif owner.new_record?
31
+ if through_record.new_record?
32
+ through_record.assign_attributes(attributes)
33
+ else
34
+ through_record.update(attributes)
35
+ end
36
+ elsif owner.new_record? || !save
28
37
  through_proxy.build(attributes)
29
38
  else
30
39
  through_proxy.create(attributes)