activerecord 4.2.0 → 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 (372) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +612 -971
  3. data/MIT-LICENSE +4 -2
  4. data/README.rdoc +13 -12
  5. data/examples/performance.rb +33 -32
  6. data/examples/simple.rb +5 -4
  7. data/lib/active_record/aggregations.rb +267 -248
  8. data/lib/active_record/association_relation.rb +24 -6
  9. data/lib/active_record/associations/alias_tracker.rb +29 -35
  10. data/lib/active_record/associations/association.rb +135 -56
  11. data/lib/active_record/associations/association_scope.rb +103 -131
  12. data/lib/active_record/associations/belongs_to_association.rb +67 -54
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
  14. data/lib/active_record/associations/builder/association.rb +27 -40
  15. data/lib/active_record/associations/builder/belongs_to.rb +69 -55
  16. data/lib/active_record/associations/builder/collection_association.rb +10 -29
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +60 -70
  18. data/lib/active_record/associations/builder/has_many.rb +8 -4
  19. data/lib/active_record/associations/builder/has_one.rb +46 -5
  20. data/lib/active_record/associations/builder/singular_association.rb +16 -10
  21. data/lib/active_record/associations/collection_association.rb +138 -274
  22. data/lib/active_record/associations/collection_proxy.rb +252 -151
  23. data/lib/active_record/associations/foreign_association.rb +20 -0
  24. data/lib/active_record/associations/has_many_association.rb +35 -83
  25. data/lib/active_record/associations/has_many_through_association.rb +62 -80
  26. data/lib/active_record/associations/has_one_association.rb +62 -49
  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 -80
  29. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
  31. data/lib/active_record/associations/join_dependency.rb +138 -162
  32. data/lib/active_record/associations/preloader/association.rb +90 -119
  33. data/lib/active_record/associations/preloader/through_association.rb +85 -65
  34. data/lib/active_record/associations/preloader.rb +92 -94
  35. data/lib/active_record/associations/singular_association.rb +18 -45
  36. data/lib/active_record/associations/through_association.rb +48 -23
  37. data/lib/active_record/associations.rb +1737 -1596
  38. data/lib/active_record/attribute_assignment.rb +56 -183
  39. data/lib/active_record/attribute_decorators.rb +39 -15
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +15 -5
  41. data/lib/active_record/attribute_methods/dirty.rb +174 -134
  42. data/lib/active_record/attribute_methods/primary_key.rb +91 -83
  43. data/lib/active_record/attribute_methods/query.rb +6 -5
  44. data/lib/active_record/attribute_methods/read.rb +20 -76
  45. data/lib/active_record/attribute_methods/serialization.rb +40 -20
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +62 -36
  47. data/lib/active_record/attribute_methods/write.rb +33 -55
  48. data/lib/active_record/attribute_methods.rb +124 -143
  49. data/lib/active_record/attributes.rb +214 -74
  50. data/lib/active_record/autosave_association.rb +115 -46
  51. data/lib/active_record/base.rb +60 -49
  52. data/lib/active_record/callbacks.rb +100 -74
  53. data/lib/active_record/coders/json.rb +3 -1
  54. data/lib/active_record/coders/yaml_column.rb +24 -12
  55. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +796 -290
  56. data/lib/active_record/connection_adapters/abstract/database_limits.rb +26 -8
  57. data/lib/active_record/connection_adapters/abstract/database_statements.rb +247 -108
  58. data/lib/active_record/connection_adapters/abstract/query_cache.rb +82 -23
  59. data/lib/active_record/connection_adapters/abstract/quoting.rb +171 -53
  60. data/lib/active_record/connection_adapters/abstract/savepoints.rb +6 -4
  61. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +74 -46
  62. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +366 -227
  63. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
  64. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +706 -222
  65. data/lib/active_record/connection_adapters/abstract/transaction.rb +191 -87
  66. data/lib/active_record/connection_adapters/abstract_adapter.rb +468 -194
  67. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +535 -597
  68. data/lib/active_record/connection_adapters/column.rb +56 -43
  69. data/lib/active_record/connection_adapters/connection_specification.rb +174 -152
  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 +59 -195
  81. data/lib/active_record/connection_adapters/postgresql/column.rb +21 -11
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +65 -115
  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 +50 -57
  85. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
  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 +5 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
  89. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -13
  91. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +7 -3
  93. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -19
  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 -9
  98. data/lib/active_record/connection_adapters/postgresql/oid/{integer.rb → oid.rb} +6 -2
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +33 -11
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -34
  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 +67 -51
  103. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +10 -5
  104. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
  106. data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
  107. data/lib/active_record/connection_adapters/postgresql/quoting.rb +144 -47
  108. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
  109. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +178 -108
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +474 -286
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +12 -8
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +558 -363
  116. data/lib/active_record/connection_adapters/schema_cache.rb +72 -25
  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 +288 -359
  126. data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
  127. data/lib/active_record/connection_handling.rb +176 -41
  128. data/lib/active_record/core.rb +266 -233
  129. data/lib/active_record/counter_cache.rb +68 -50
  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 -105
  136. data/lib/active_record/enum.rb +164 -88
  137. data/lib/active_record/errors.rb +189 -53
  138. data/lib/active_record/explain.rb +23 -11
  139. data/lib/active_record/explain_registry.rb +4 -2
  140. data/lib/active_record/explain_subscriber.rb +11 -6
  141. data/lib/active_record/fixture_set/file.rb +35 -9
  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 +226 -495
  147. data/lib/active_record/gem_version.rb +4 -2
  148. data/lib/active_record/inheritance.rb +158 -112
  149. data/lib/active_record/insert_all.rb +179 -0
  150. data/lib/active_record/integration.rb +123 -29
  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 +3 -2
  154. data/lib/active_record/locking/optimistic.rb +91 -98
  155. data/lib/active_record/locking/pessimistic.rb +18 -6
  156. data/lib/active_record/log_subscriber.rb +76 -33
  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 +177 -90
  161. data/lib/active_record/migration/compatibility.rb +244 -0
  162. data/lib/active_record/migration/join_table.rb +8 -6
  163. data/lib/active_record/migration.rb +634 -288
  164. data/lib/active_record/model_schema.rb +314 -112
  165. data/lib/active_record/nested_attributes.rb +266 -214
  166. data/lib/active_record/no_touching.rb +15 -2
  167. data/lib/active_record/null_relation.rb +24 -37
  168. data/lib/active_record/persistence.rb +559 -124
  169. data/lib/active_record/query_cache.rb +19 -23
  170. data/lib/active_record/querying.rb +43 -29
  171. data/lib/active_record/railtie.rb +148 -47
  172. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  173. data/lib/active_record/railties/console_sandbox.rb +2 -0
  174. data/lib/active_record/railties/controller_runtime.rb +34 -33
  175. data/lib/active_record/railties/databases.rake +338 -202
  176. data/lib/active_record/readonly_attributes.rb +5 -4
  177. data/lib/active_record/reflection.rb +460 -299
  178. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  179. data/lib/active_record/relation/batches.rb +207 -55
  180. data/lib/active_record/relation/calculations.rb +269 -248
  181. data/lib/active_record/relation/delegation.rb +70 -80
  182. data/lib/active_record/relation/finder_methods.rb +279 -255
  183. data/lib/active_record/relation/from_clause.rb +26 -0
  184. data/lib/active_record/relation/merger.rb +83 -69
  185. data/lib/active_record/relation/predicate_builder/array_handler.rb +27 -25
  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 +7 -1
  192. data/lib/active_record/relation/predicate_builder.rb +116 -92
  193. data/lib/active_record/relation/query_attribute.rb +50 -0
  194. data/lib/active_record/relation/query_methods.rb +574 -391
  195. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  196. data/lib/active_record/relation/spawn_methods.rb +18 -16
  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 +518 -340
  200. data/lib/active_record/result.rb +79 -42
  201. data/lib/active_record/runtime_registry.rb +6 -4
  202. data/lib/active_record/sanitization.rb +144 -121
  203. data/lib/active_record/schema.rb +21 -24
  204. data/lib/active_record/schema_dumper.rb +112 -93
  205. data/lib/active_record/schema_migration.rb +24 -20
  206. data/lib/active_record/scoping/default.rb +101 -84
  207. data/lib/active_record/scoping/named.rb +86 -33
  208. data/lib/active_record/scoping.rb +45 -26
  209. data/lib/active_record/secure_token.rb +40 -0
  210. data/lib/active_record/serialization.rb +5 -5
  211. data/lib/active_record/statement_cache.rb +73 -36
  212. data/lib/active_record/store.rb +127 -42
  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 +309 -99
  216. data/lib/active_record/tasks/mysql_database_tasks.rb +58 -88
  217. data/lib/active_record/tasks/postgresql_database_tasks.rb +82 -31
  218. data/lib/active_record/tasks/sqlite_database_tasks.rb +38 -16
  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 +86 -40
  222. data/lib/active_record/touch_later.rb +66 -0
  223. data/lib/active_record/transactions.rb +215 -139
  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 +4 -41
  227. data/lib/active_record/type/date_time.rb +4 -38
  228. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  229. data/lib/active_record/type/hash_lookup_type_map.rb +13 -5
  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 +30 -15
  233. data/lib/active_record/type/text.rb +2 -2
  234. data/lib/active_record/type/time.rb +11 -16
  235. data/lib/active_record/type/type_map.rb +15 -17
  236. data/lib/active_record/type/unsigned_integer.rb +9 -7
  237. data/lib/active_record/type.rb +78 -23
  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 +13 -4
  243. data/lib/active_record/validations/length.rb +26 -0
  244. data/lib/active_record/validations/presence.rb +14 -13
  245. data/lib/active_record/validations/uniqueness.rb +43 -46
  246. data/lib/active_record/validations.rb +39 -35
  247. data/lib/active_record/version.rb +3 -1
  248. data/lib/active_record.rb +43 -21
  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 +42 -37
  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 → migration.rb.tt} +11 -8
  335. data/lib/rails/generators/active_record/migration.rb +31 -1
  336. data/lib/rails/generators/active_record/model/model_generator.rb +19 -22
  337. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  338. data/lib/rails/generators/active_record.rb +7 -5
  339. metadata +166 -60
  340. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  341. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  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 -23
  345. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  346. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  347. data/lib/active_record/attribute.rb +0 -149
  348. data/lib/active_record/attribute_set/builder.rb +0 -86
  349. data/lib/active_record/attribute_set.rb +0 -77
  350. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  351. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  352. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  353. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  354. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  355. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  356. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  357. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  358. data/lib/active_record/type/big_integer.rb +0 -13
  359. data/lib/active_record/type/binary.rb +0 -50
  360. data/lib/active_record/type/boolean.rb +0 -30
  361. data/lib/active_record/type/decimal.rb +0 -40
  362. data/lib/active_record/type/decorator.rb +0 -14
  363. data/lib/active_record/type/float.rb +0 -19
  364. data/lib/active_record/type/integer.rb +0 -55
  365. data/lib/active_record/type/mutable.rb +0 -16
  366. data/lib/active_record/type/numeric.rb +0 -36
  367. data/lib/active_record/type/string.rb +0 -36
  368. data/lib/active_record/type/time_value.rb +0 -38
  369. data/lib/active_record/type/value.rb +0 -101
  370. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -22
  371. data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
  372. /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Associations
3
5
  # = Active Record Association Collection
@@ -10,9 +12,9 @@ module ActiveRecord
10
12
  # HasManyAssociation => has_many
11
13
  # HasManyThroughAssociation + ThroughAssociation => has_many :through
12
14
  #
13
- # CollectionAssociation class provides common methods to the collections
15
+ # The CollectionAssociation class provides common methods to the collections
14
16
  # defined by +has_and_belongs_to_many+, +has_many+ or +has_many+ with
15
- # +:through association+ option.
17
+ # the +:through association+ option.
16
18
  #
17
19
  # You need to be careful with assumptions regarding the target: The proxy
18
20
  # does not fetch records from the database until it needs them, but new
@@ -24,22 +26,14 @@ module ActiveRecord
24
26
  # If you need to work on all current children, new and existing records,
25
27
  # +load_target+ and the +loaded+ flag are your friends.
26
28
  class CollectionAssociation < Association #:nodoc:
27
-
28
29
  # Implements the reader method, e.g. foo.items for Foo.has_many :items
29
- def reader(force_reload = false)
30
- if force_reload
31
- klass.uncached { reload }
32
- elsif stale_target?
30
+ def reader
31
+ if stale_target?
33
32
  reload
34
33
  end
35
34
 
36
- if owner.new_record?
37
- # Cache the proxy separately before the owner has an id
38
- # or else a post-save proxy will still lack the id
39
- @new_record_proxy ||= CollectionProxy.create(klass, self)
40
- else
41
- @proxy ||= CollectionProxy.create(klass, self)
42
- end
35
+ @proxy ||= CollectionProxy.create(klass, self)
36
+ @proxy.reset_scope
43
37
  end
44
38
 
45
39
  # Implements the writer method, e.g. foo.items= for Foo.has_many :items
@@ -50,107 +44,75 @@ module ActiveRecord
50
44
  # Implements the ids reader method, e.g. foo.item_ids for Foo.has_many :items
51
45
  def ids_reader
52
46
  if loaded?
53
- load_target.map do |record|
54
- record.send(reflection.association_primary_key)
55
- end
47
+ target.pluck(reflection.association_primary_key)
48
+ elsif !target.empty?
49
+ load_target.pluck(reflection.association_primary_key)
56
50
  else
57
- column = "#{reflection.quoted_table_name}.#{reflection.association_primary_key}"
58
- scope.pluck(column)
51
+ @association_ids ||= scope.pluck(reflection.association_primary_key)
59
52
  end
60
53
  end
61
54
 
62
55
  # Implements the ids writer method, e.g. foo.item_ids= for Foo.has_many :items
63
56
  def ids_writer(ids)
64
- pk_type = reflection.primary_key_type
65
- ids = Array(ids).reject { |id| id.blank? }
66
- ids.map! { |i| pk_type.type_cast_from_user(i) }
67
- replace(klass.find(ids).index_by { |r| r.id }.values_at(*ids))
57
+ primary_key = reflection.association_primary_key
58
+ pk_type = klass.type_for_attribute(primary_key)
59
+ ids = Array(ids).reject(&:blank?)
60
+ ids.map! { |i| pk_type.cast(i) }
61
+
62
+ records = klass.where(primary_key => ids).index_by do |r|
63
+ r.public_send(primary_key)
64
+ end.values_at(*ids).compact
65
+
66
+ if records.size != ids.size
67
+ found_ids = records.map { |record| record.public_send(primary_key) }
68
+ not_found_ids = ids - found_ids
69
+ klass.all.raise_record_not_found_exception!(ids, records.size, ids.size, primary_key, not_found_ids)
70
+ else
71
+ replace(records)
72
+ end
68
73
  end
69
74
 
70
75
  def reset
71
76
  super
72
77
  @target = []
73
- end
74
-
75
- def select(*fields)
76
- if block_given?
77
- load_target.select.each { |e| yield e }
78
- else
79
- scope.select(*fields)
80
- end
78
+ @association_ids = nil
81
79
  end
82
80
 
83
81
  def find(*args)
84
- if block_given?
85
- load_target.find(*args) { |*block_args| yield(*block_args) }
86
- else
87
- if options[:inverse_of] && loaded?
88
- args_flatten = args.flatten
89
- raise RecordNotFound, "Couldn't find #{scope.klass.name} without an ID" if args_flatten.blank?
90
- result = find_by_scan(*args)
91
-
92
- result_size = Array(result).size
93
- if !result || result_size != args_flatten.size
94
- scope.raise_record_not_found_exception!(args_flatten, result_size, args_flatten.size)
95
- else
96
- result
97
- end
98
- else
99
- scope.find(*args)
100
- end
101
- end
102
- end
103
-
104
- def first(*args)
105
- first_nth_or_last(:first, *args)
106
- end
107
-
108
- def second(*args)
109
- first_nth_or_last(:second, *args)
110
- end
111
-
112
- def third(*args)
113
- first_nth_or_last(:third, *args)
114
- end
82
+ if options[:inverse_of] && loaded?
83
+ args_flatten = args.flatten
84
+ model = scope.klass
115
85
 
116
- def fourth(*args)
117
- first_nth_or_last(:fourth, *args)
118
- end
86
+ if args_flatten.blank?
87
+ error_message = "Couldn't find #{model.name} without an ID"
88
+ raise RecordNotFound.new(error_message, model.name, model.primary_key, args)
89
+ end
119
90
 
120
- def fifth(*args)
121
- first_nth_or_last(:fifth, *args)
122
- end
91
+ result = find_by_scan(*args)
123
92
 
124
- def forty_two(*args)
125
- first_nth_or_last(:forty_two, *args)
126
- end
127
-
128
- def last(*args)
129
- first_nth_or_last(:last, *args)
93
+ result_size = Array(result).size
94
+ if !result || result_size != args_flatten.size
95
+ scope.raise_record_not_found_exception!(args_flatten, result_size, args_flatten.size)
96
+ else
97
+ result
98
+ end
99
+ else
100
+ scope.find(*args)
101
+ end
130
102
  end
131
103
 
132
104
  def build(attributes = {}, &block)
133
105
  if attributes.is_a?(Array)
134
106
  attributes.collect { |attr| build(attr, &block) }
135
107
  else
136
- add_to_target(build_record(attributes)) do |record|
137
- yield(record) if block_given?
138
- end
108
+ add_to_target(build_record(attributes, &block))
139
109
  end
140
110
  end
141
111
 
142
- def create(attributes = {}, &block)
143
- _create_record(attributes, &block)
144
- end
145
-
146
- def create!(attributes = {}, &block)
147
- _create_record(attributes, true, &block)
148
- end
149
-
150
- # Add +records+ to this association. Returns +self+ so method calls may
151
- # be chained. Since << flattens its argument list and inserts each record,
152
- # +push+ and +concat+ behave identically.
112
+ # Add +records+ to this association. Since +<<+ flattens its argument list
113
+ # and inserts each record, +push+ and +concat+ behave identically.
153
114
  def concat(*records)
115
+ records = records.flatten
154
116
  if owner.new_record?
155
117
  load_target
156
118
  concat_records(records)
@@ -193,12 +155,12 @@ module ActiveRecord
193
155
  end
194
156
 
195
157
  dependent = if dependent
196
- dependent
197
- elsif options[:dependent] == :destroy
198
- :delete_all
199
- else
200
- options[:dependent]
201
- end
158
+ dependent
159
+ elsif options[:dependent] == :destroy
160
+ :delete_all
161
+ else
162
+ options[:dependent]
163
+ end
202
164
 
203
165
  delete_or_nullify_all_records(dependent).tap do
204
166
  reset
@@ -216,32 +178,6 @@ module ActiveRecord
216
178
  end
217
179
  end
218
180
 
219
- # Count all records using SQL. Construct options and pass them with
220
- # scope to the target class's +count+.
221
- def count(column_name = nil, count_options = {})
222
- # TODO: Remove count_options argument as soon we remove support to
223
- # activerecord-deprecated_finders.
224
- column_name, count_options = nil, column_name if column_name.is_a?(Hash)
225
-
226
- relation = scope
227
- if association_scope.distinct_value
228
- # This is needed because 'SELECT count(DISTINCT *)..' is not valid SQL.
229
- column_name ||= reflection.klass.primary_key
230
- relation = relation.distinct
231
- end
232
-
233
- value = relation.count(column_name)
234
-
235
- limit = options[:limit]
236
- offset = options[:offset]
237
-
238
- if limit || offset
239
- [ [value - offset.to_i, 0].max, limit.to_i ].min
240
- else
241
- value
242
- end
243
- end
244
-
245
181
  # Removes +records+ from this association calling +before_remove+ and
246
182
  # +after_remove+ callbacks.
247
183
  #
@@ -250,12 +186,7 @@ module ActiveRecord
250
186
  # are actually removed from the database, that depends precisely on
251
187
  # +delete_records+. They are in any case removed from the collection.
252
188
  def delete(*records)
253
- return if records.empty?
254
- _options = records.extract_options!
255
- dependent = _options[:dependent] || options[:dependent]
256
-
257
- records = find(records) if records.any? { |record| record.kind_of?(Fixnum) || record.kind_of?(String) }
258
- delete_or_destroy(records, dependent)
189
+ delete_or_destroy(records, options[:dependent])
259
190
  end
260
191
 
261
192
  # Deletes the +records+ and removes them from this association calling
@@ -264,8 +195,6 @@ module ActiveRecord
264
195
  # Note that this method removes records from the database ignoring the
265
196
  # +:dependent+ option.
266
197
  def destroy(*records)
267
- return if records.empty?
268
- records = find(records) if records.any? { |record| record.kind_of?(Fixnum) || record.kind_of?(String) }
269
198
  delete_or_destroy(records, :destroy)
270
199
  end
271
200
 
@@ -281,30 +210,19 @@ module ActiveRecord
281
210
  # +count_records+, which is a method descendants have to provide.
282
211
  def size
283
212
  if !find_target? || loaded?
284
- if association_scope.distinct_value
285
- target.uniq.size
286
- else
287
- target.size
288
- end
289
- elsif !loaded? && !association_scope.group_values.empty?
213
+ target.size
214
+ elsif @association_ids
215
+ @association_ids.size
216
+ elsif !association_scope.group_values.empty?
290
217
  load_target.size
291
- elsif !loaded? && !association_scope.distinct_value && target.is_a?(Array)
292
- unsaved_records = target.select { |r| r.new_record? }
218
+ elsif !association_scope.distinct_value && !target.empty?
219
+ unsaved_records = target.select(&:new_record?)
293
220
  unsaved_records.size + count_records
294
221
  else
295
222
  count_records
296
223
  end
297
224
  end
298
225
 
299
- # Returns the size of the collection calling +size+ on the target.
300
- #
301
- # If the collection has been already loaded +length+ and +size+ are
302
- # equivalent. If not and you are going to need the records anyway this
303
- # method will take one less query. Otherwise +size+ is more efficient.
304
- def length
305
- load_target.size
306
- end
307
-
308
226
  # Returns true if the collection is empty.
309
227
  #
310
228
  # If the collection has been loaded
@@ -314,41 +232,13 @@ module ActiveRecord
314
232
  # loaded and you are going to fetch the records anyway it is better to
315
233
  # check <tt>collection.length.zero?</tt>.
316
234
  def empty?
317
- if loaded?
235
+ if loaded? || @association_ids || reflection.has_cached_counter?
318
236
  size.zero?
319
237
  else
320
- @target.blank? && !scope.exists?
321
- end
322
- end
323
-
324
- # Returns true if the collections is not empty.
325
- # Equivalent to +!collection.empty?+.
326
- def any?
327
- if block_given?
328
- load_target.any? { |*block_args| yield(*block_args) }
329
- else
330
- !empty?
238
+ target.empty? && !scope.exists?
331
239
  end
332
240
  end
333
241
 
334
- # Returns true if the collection has more than 1 record.
335
- # Equivalent to +collection.size > 1+.
336
- def many?
337
- if block_given?
338
- load_target.many? { |*block_args| yield(*block_args) }
339
- else
340
- size > 1
341
- end
342
- end
343
-
344
- def distinct
345
- seen = {}
346
- load_target.find_all do |record|
347
- seen[record.id] = true unless seen.key?(record.id)
348
- end
349
- end
350
- alias uniq distinct
351
-
352
242
  # Replace this collection with +other_array+. This will perform a diff
353
243
  # and delete/add only records that have changed.
354
244
  def replace(other_array)
@@ -361,6 +251,8 @@ module ActiveRecord
361
251
  replace_common_records_in_memory(other_array, original_target)
362
252
  if other_array != original_target
363
253
  transaction { replace_records(other_array, original_target) }
254
+ else
255
+ other_array
364
256
  end
365
257
  end
366
258
  end
@@ -393,25 +285,9 @@ module ActiveRecord
393
285
  replace_on_target(record, index, skip_callbacks, &block)
394
286
  end
395
287
 
396
- def replace_on_target(record, index, skip_callbacks)
397
- callback(:before_add, record) unless skip_callbacks
398
- yield(record) if block_given?
399
-
400
- if index
401
- @target[index] = record
402
- else
403
- @target << record
404
- end
405
-
406
- callback(:after_add, record) unless skip_callbacks
407
- set_inverse_instance(record)
408
-
409
- record
410
- end
411
-
412
- def scope(opts = {})
413
- scope = super()
414
- scope.none! if opts.fetch(:nullify, true) && null_scope?
288
+ def scope
289
+ scope = super
290
+ scope.none! if null_scope?
415
291
  scope
416
292
  end
417
293
 
@@ -419,34 +295,13 @@ module ActiveRecord
419
295
  owner.new_record? && !foreign_key_present?
420
296
  end
421
297
 
422
- private
423
- def get_records
424
- if reflection.scope_chain.any?(&:any?) ||
425
- scope.eager_loading? ||
426
- klass.current_scope ||
427
- klass.default_scopes.any?
428
-
429
- return scope.to_a
430
- end
431
-
432
- conn = klass.connection
433
- sc = reflection.association_scope_cache(conn, owner) do
434
- StatementCache.create(conn) { |params|
435
- as = AssociationScope.create { params.bind }
436
- target_scope.merge as.scope(self, conn)
437
- }
438
- end
439
-
440
- binds = AssociationScope.get_bind_values(owner, reflection.chain)
441
- sc.execute binds, klass, klass.connection
298
+ def find_from_target?
299
+ loaded? ||
300
+ owner.new_record? ||
301
+ target.any? { |record| record.new_record? || record.changed? }
442
302
  end
443
303
 
444
- def find_target
445
- records = get_records
446
- records.each { |record| set_inverse_instance(record) }
447
- records
448
- end
449
-
304
+ private
450
305
  # We have some records loaded from the database (persisted) and some that are
451
306
  # in-memory (memory). The same record may be represented in the persisted array
452
307
  # and in the memory array.
@@ -464,7 +319,7 @@ module ActiveRecord
464
319
  persisted.map! do |record|
465
320
  if mem_record = memory.delete(record)
466
321
 
467
- ((record.attribute_names & mem_record.attribute_names) - mem_record.changes.keys).each do |name|
322
+ ((record.attribute_names & mem_record.attribute_names) - mem_record.changed_attribute_names_to_save).each do |name|
468
323
  mem_record[name] = record[name]
469
324
  end
470
325
 
@@ -485,28 +340,35 @@ module ActiveRecord
485
340
  if attributes.is_a?(Array)
486
341
  attributes.collect { |attr| _create_record(attr, raise, &block) }
487
342
  else
343
+ record = build_record(attributes, &block)
488
344
  transaction do
489
- add_to_target(build_record(attributes)) do |record|
490
- yield(record) if block_given?
491
- insert_record(record, true, raise)
345
+ result = nil
346
+ add_to_target(record) do
347
+ result = insert_record(record, true, raise) {
348
+ @_was_loaded = loaded?
349
+ }
492
350
  end
351
+ raise ActiveRecord::Rollback unless result
493
352
  end
353
+ record
494
354
  end
495
355
  end
496
356
 
497
357
  # Do the relevant stuff to insert the given record into the association collection.
498
- def insert_record(record, validate = true, raise = false)
499
- raise NotImplementedError
500
- end
501
-
502
- def create_scope
503
- scope.scope_for_create.stringify_keys
358
+ def insert_record(record, validate = true, raise = false, &block)
359
+ if raise
360
+ record.save!(validate: validate, &block)
361
+ else
362
+ record.save(validate: validate, &block)
363
+ end
504
364
  end
505
365
 
506
366
  def delete_or_destroy(records, method)
367
+ return if records.empty?
368
+ records = find(records) if records.any? { |record| record.kind_of?(Integer) || record.kind_of?(String) }
507
369
  records = records.flatten
508
370
  records.each { |record| raise_on_type_mismatch!(record) }
509
- existing_records = records.reject { |r| r.new_record? }
371
+ existing_records = records.reject(&:new_record?)
510
372
 
511
373
  if existing_records.empty?
512
374
  remove_records(existing_records, records, method)
@@ -519,21 +381,23 @@ module ActiveRecord
519
381
  records.each { |record| callback(:before_remove, record) }
520
382
 
521
383
  delete_records(existing_records, method) if existing_records.any?
522
- records.each { |record| target.delete(record) }
384
+ @target -= records
385
+ @association_ids = nil
523
386
 
524
387
  records.each { |record| callback(:after_remove, record) }
525
388
  end
526
389
 
527
- # Delete the given records from the association, using one of the methods :destroy,
528
- # :delete_all or :nullify (or nil, in which case a default is used).
390
+ # Delete the given records from the association,
391
+ # using one of the methods +:destroy+, +:delete_all+
392
+ # or +:nullify+ (or +nil+, in which case a default is used).
529
393
  def delete_records(records, method)
530
394
  raise NotImplementedError
531
395
  end
532
396
 
533
397
  def replace_records(new_target, original_target)
534
- delete(target - new_target)
398
+ delete(difference(target, new_target))
535
399
 
536
- unless concat(new_target - target)
400
+ unless concat(difference(new_target, target))
537
401
  @target = original_target
538
402
  raise RecordNotSaved, "Failed to replace #{reflection.name} because one or more of the " \
539
403
  "new records could not be saved."
@@ -543,24 +407,53 @@ module ActiveRecord
543
407
  end
544
408
 
545
409
  def replace_common_records_in_memory(new_target, original_target)
546
- common_records = new_target & original_target
410
+ common_records = intersection(new_target, original_target)
547
411
  common_records.each do |record|
548
412
  skip_callbacks = true
549
413
  replace_on_target(record, @target.index(record), skip_callbacks)
550
414
  end
551
415
  end
552
416
 
553
- def concat_records(records, should_raise = false)
417
+ def concat_records(records, raise = false)
554
418
  result = true
555
419
 
556
- records.flatten.each do |record|
420
+ records.each do |record|
557
421
  raise_on_type_mismatch!(record)
558
- add_to_target(record) do |rec|
559
- result &&= insert_record(rec, true, should_raise) unless owner.new_record?
422
+ add_to_target(record) do
423
+ unless owner.new_record?
424
+ result &&= insert_record(record, true, raise) {
425
+ @_was_loaded = loaded?
426
+ }
427
+ end
560
428
  end
561
429
  end
562
430
 
563
- result && records
431
+ raise ActiveRecord::Rollback unless result
432
+
433
+ records
434
+ end
435
+
436
+ def replace_on_target(record, index, skip_callbacks)
437
+ callback(:before_add, record) unless skip_callbacks
438
+
439
+ set_inverse_instance(record)
440
+
441
+ @_was_loaded = true
442
+
443
+ yield(record) if block_given?
444
+
445
+ if index
446
+ target[index] = record
447
+ elsif @_was_loaded || !loaded?
448
+ @association_ids = nil
449
+ target << record
450
+ end
451
+
452
+ callback(:after_add, record) unless skip_callbacks
453
+
454
+ record
455
+ ensure
456
+ @_was_loaded = nil
564
457
  end
565
458
 
566
459
  def callback(method, record)
@@ -574,31 +467,12 @@ module ActiveRecord
574
467
  owner.class.send(full_callback_name)
575
468
  end
576
469
 
577
- # Should we deal with assoc.first or assoc.last by issuing an independent query to
578
- # the database, or by getting the target, and then taking the first/last item from that?
579
- #
580
- # If the args is just a non-empty options hash, go to the database.
581
- #
582
- # Otherwise, go to the database only if none of the following are true:
583
- # * target already loaded
584
- # * owner is new record
585
- # * target contains new or changed record(s)
586
- def fetch_first_nth_or_last_using_find?(args)
587
- if args.first.is_a?(Hash)
588
- true
589
- else
590
- !(loaded? ||
591
- owner.new_record? ||
592
- target.any? { |record| record.new_record? || record.changed? })
593
- end
594
- end
595
-
596
470
  def include_in_memory?(record)
597
471
  if reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
598
472
  assoc = owner.association(reflection.through_reflection.name)
599
473
  assoc.reader.any? { |source|
600
- target = source.send(reflection.source_reflection.name)
601
- target.respond_to?(:include?) ? target.include?(record) : target == record
474
+ target_reflection = source.send(reflection.source_reflection.name)
475
+ target_reflection.respond_to?(:include?) ? target_reflection.include?(record) : target_reflection == record
602
476
  } || target.include?(record)
603
477
  else
604
478
  target.include?(record)
@@ -609,7 +483,7 @@ module ActiveRecord
609
483
  # specified, then #find scans the entire collection.
610
484
  def find_by_scan(*args)
611
485
  expects_array = args.first.kind_of?(Array)
612
- ids = args.flatten.compact.map{ |arg| arg.to_s }.uniq
486
+ ids = args.flatten.compact.map(&:to_s).uniq
613
487
 
614
488
  if ids.size == 1
615
489
  id = ids.first
@@ -619,16 +493,6 @@ module ActiveRecord
619
493
  load_target.select { |r| ids.include?(r.id.to_s) }
620
494
  end
621
495
  end
622
-
623
- # Fetches the first/last using SQL if possible, otherwise from the target array.
624
- def first_nth_or_last(type, *args)
625
- args.shift if args.first.is_a?(Hash) && args.first.empty?
626
-
627
- collection = fetch_first_nth_or_last_using_find?(args) ? scope : load_target
628
- collection.send(type, *args).tap do |record|
629
- set_inverse_instance record if record.is_a? ActiveRecord::Base
630
- end
631
- end
632
496
  end
633
497
  end
634
498
  end