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,19 +1,20 @@
1
- require 'active_record/associations/join_dependency/join_part'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record/associations/join_dependency/join_part"
4
+ require "active_support/core_ext/array/extract"
2
5
 
3
6
  module ActiveRecord
4
7
  module Associations
5
8
  class JoinDependency # :nodoc:
6
9
  class JoinAssociation < JoinPart # :nodoc:
7
- # The reflection of the association represented
8
- attr_reader :reflection
9
-
10
- attr_accessor :tables
10
+ attr_reader :reflection, :tables
11
+ attr_accessor :table
11
12
 
12
13
  def initialize(reflection, children)
13
14
  super(reflection.klass, children)
14
15
 
15
- @reflection = reflection
16
- @tables = nil
16
+ @reflection = reflection
17
+ @tables = nil
17
18
  end
18
19
 
19
20
  def match?(other)
@@ -21,101 +22,58 @@ module ActiveRecord
21
22
  super && reflection == other.reflection
22
23
  end
23
24
 
24
- JoinInformation = Struct.new :joins, :binds
25
-
26
- def join_constraints(foreign_table, foreign_klass, node, join_type, tables, scope_chain, chain)
27
- joins = []
28
- bind_values = []
29
- tables = tables.reverse
30
-
31
- scope_chain_index = 0
32
- scope_chain = scope_chain.reverse
25
+ def join_constraints(foreign_table, foreign_klass, join_type, alias_tracker)
26
+ joins = []
33
27
 
34
28
  # The chain starts with the target table, but we want to end with it here (makes
35
29
  # more sense in this context), so we reverse
36
- chain.reverse_each do |reflection|
37
- table = tables.shift
30
+ reflection.chain.reverse_each.with_index(1) do |reflection, i|
31
+ table = tables[-i]
38
32
  klass = reflection.klass
39
33
 
40
- join_keys = reflection.join_keys(klass)
41
- key = join_keys.key
42
- foreign_key = join_keys.foreign_key
43
-
44
- constraint = build_constraint(klass, table, key, foreign_table, foreign_key)
45
-
46
- scope_chain_items = scope_chain[scope_chain_index].map do |item|
47
- if item.is_a?(Relation)
48
- item
49
- else
50
- ActiveRecord::Relation.create(klass, table).instance_exec(node, &item)
51
- end
52
- end
53
- scope_chain_index += 1
54
-
55
- scope_chain_items.concat [klass.send(:build_default_scope, ActiveRecord::Relation.create(klass, table))].compact
34
+ join_scope = reflection.join_scope(table, foreign_table, foreign_klass)
56
35
 
57
- rel = scope_chain_items.inject(scope_chain_items.shift) do |left, right|
58
- left.merge right
59
- end
36
+ arel = join_scope.arel(alias_tracker.aliases)
37
+ nodes = arel.constraints.first
60
38
 
61
- if rel && !rel.arel.constraints.empty?
62
- bind_values.concat rel.bind_values
63
- constraint = constraint.and rel.arel.constraints
39
+ others = nodes.children.extract! do |node|
40
+ Arel.fetch_attribute(node) { |attr| attr.relation.name != table.name }
64
41
  end
65
42
 
66
- if reflection.type
67
- value = foreign_klass.base_class.name
68
- column = klass.columns_hash[reflection.type.to_s]
43
+ joins << table.create_join(table, table.create_on(nodes), join_type)
69
44
 
70
- substitute = klass.connection.substitute_at(column)
71
- bind_values.push [column, value]
72
- constraint = constraint.and table[reflection.type].eq substitute
45
+ unless others.empty?
46
+ joins.concat arel.join_sources
47
+ append_constraints(joins.last, others)
73
48
  end
74
49
 
75
- joins << table.create_join(table, table.create_on(constraint), join_type)
76
-
77
50
  # The current table in this iteration becomes the foreign table in the next
78
51
  foreign_table, foreign_klass = table, klass
79
52
  end
80
53
 
81
- JoinInformation.new joins, bind_values
54
+ joins
82
55
  end
83
56
 
84
- # Builds equality condition.
85
- #
86
- # Example:
87
- #
88
- # class Physician < ActiveRecord::Base
89
- # has_many :appointments
90
- # end
91
- #
92
- # If I execute `Physician.joins(:appointments).to_a` then
93
- # klass # => Physician
94
- # table # => #<Arel::Table @name="appointments" ...>
95
- # key # => physician_id
96
- # foreign_table # => #<Arel::Table @name="physicians" ...>
97
- # foreign_key # => id
98
- #
99
- def build_constraint(klass, table, key, foreign_table, foreign_key)
100
- constraint = table[key].eq(foreign_table[foreign_key])
101
-
102
- if klass.finder_needs_type_condition?
103
- constraint = table.create_and([
104
- constraint,
105
- klass.send(:type_condition, table)
106
- ])
107
- end
108
-
109
- constraint
57
+ def tables=(tables)
58
+ @tables = tables
59
+ @table = tables.first
110
60
  end
111
61
 
112
- def table
113
- tables.first
114
- end
62
+ def readonly?
63
+ return @readonly if defined?(@readonly)
115
64
 
116
- def aliased_table_name
117
- table.table_alias || table.name
65
+ @readonly = reflection.scope && reflection.scope_for(base_klass.unscoped).readonly_value
118
66
  end
67
+
68
+ private
69
+ def append_constraints(join, constraints)
70
+ if join.is_a?(Arel::Nodes::StringJoin)
71
+ join_string = table.create_and(constraints.unshift(join.left))
72
+ join.left = Arel.sql(base_klass.connection.visitor.compile(join_string))
73
+ else
74
+ join.right.expr.children.concat(constraints)
75
+ end
76
+ end
119
77
  end
120
78
  end
121
79
  end
@@ -1,20 +1,21 @@
1
- require 'active_record/associations/join_dependency/join_part'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record/associations/join_dependency/join_part"
2
4
 
3
5
  module ActiveRecord
4
6
  module Associations
5
7
  class JoinDependency # :nodoc:
6
8
  class JoinBase < JoinPart # :nodoc:
7
- def match?(other)
8
- return true if self == other
9
- super && base_klass == other.base_klass
10
- end
9
+ attr_reader :table
11
10
 
12
- def table
13
- base_klass.arel_table
11
+ def initialize(base_klass, table, children)
12
+ super(base_klass, children)
13
+ @table = table
14
14
  end
15
15
 
16
- def aliased_table_name
17
- base_klass.table_name
16
+ def match?(other)
17
+ return true if self == other
18
+ super && base_klass == other.base_klass
18
19
  end
19
20
  end
20
21
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Associations
3
5
  class JoinDependency # :nodoc:
@@ -15,17 +17,13 @@ module ActiveRecord
15
17
  # association.
16
18
  attr_reader :base_klass, :children
17
19
 
18
- delegate :table_name, :column_names, :primary_key, :to => :base_klass
20
+ delegate :table_name, :column_names, :primary_key, to: :base_klass
19
21
 
20
22
  def initialize(base_klass, children)
21
23
  @base_klass = base_klass
22
24
  @children = children
23
25
  end
24
26
 
25
- def name
26
- reflection.name
27
- end
28
-
29
27
  def match?(other)
30
28
  self.class == other.class
31
29
  end
@@ -35,13 +33,15 @@ module ActiveRecord
35
33
  children.each { |child| child.each(&block) }
36
34
  end
37
35
 
38
- # An Arel::Table for the active_record
39
- def table
40
- raise NotImplementedError
36
+ def each_children(&block)
37
+ children.each do |child|
38
+ yield self, child
39
+ child.each_children(&block)
40
+ end
41
41
  end
42
42
 
43
- # The alias for the active_record's table
44
- def aliased_table_name
43
+ # An Arel::Table for the active_record
44
+ def table
45
45
  raise NotImplementedError
46
46
  end
47
47
 
@@ -54,16 +54,16 @@ module ActiveRecord
54
54
  length = column_names_with_alias.length
55
55
 
56
56
  while index < length
57
- column_name, alias_name = column_names_with_alias[index]
58
- hash[column_name] = row[alias_name]
57
+ column = column_names_with_alias[index]
58
+ hash[column.name] = row[column.alias]
59
59
  index += 1
60
60
  end
61
61
 
62
62
  hash
63
63
  end
64
64
 
65
- def instantiate(row, aliases)
66
- base_klass.instantiate(extract_record(row, aliases))
65
+ def instantiate(row, aliases, &block)
66
+ base_klass.instantiate(extract_record(row, aliases), &block)
67
67
  end
68
68
  end
69
69
  end
@@ -1,52 +1,45 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Associations
3
5
  class JoinDependency # :nodoc:
4
- autoload :JoinBase, 'active_record/associations/join_dependency/join_base'
5
- autoload :JoinAssociation, 'active_record/associations/join_dependency/join_association'
6
+ autoload :JoinBase, "active_record/associations/join_dependency/join_base"
7
+ autoload :JoinAssociation, "active_record/associations/join_dependency/join_association"
6
8
 
7
9
  class Aliases # :nodoc:
8
10
  def initialize(tables)
9
11
  @tables = tables
10
- @alias_cache = tables.each_with_object({}) { |table,h|
11
- h[table.node] = table.columns.each_with_object({}) { |column,i|
12
+ @alias_cache = tables.each_with_object({}) { |table, h|
13
+ h[table.node] = table.columns.each_with_object({}) { |column, i|
12
14
  i[column.name] = column.alias
13
15
  }
14
16
  }
15
- @name_and_alias_cache = tables.each_with_object({}) { |table,h|
16
- h[table.node] = table.columns.map { |column|
17
- [column.name, column.alias]
18
- }
17
+ @columns_cache = tables.each_with_object({}) { |table, h|
18
+ h[table.node] = table.columns
19
19
  }
20
20
  end
21
21
 
22
22
  def columns
23
- @tables.flat_map { |t| t.column_aliases }
23
+ @tables.flat_map(&:column_aliases)
24
24
  end
25
25
 
26
- # An array of [column_name, alias] pairs for the table
27
26
  def column_aliases(node)
28
- @name_and_alias_cache[node]
27
+ @columns_cache[node]
29
28
  end
30
29
 
31
30
  def column_alias(node, column)
32
31
  @alias_cache[node][column]
33
32
  end
34
33
 
35
- class Table < Struct.new(:node, :columns)
36
- def table
37
- Arel::Nodes::TableAlias.new node.table, node.aliased_table_name
38
- end
39
-
34
+ Table = Struct.new(:node, :columns) do # :nodoc:
40
35
  def column_aliases
41
- t = table
36
+ t = node.table
42
37
  columns.map { |column| t[column.name].as Arel.sql column.alias }
43
38
  end
44
39
  end
45
40
  Column = Struct.new(:name, :alias)
46
41
  end
47
42
 
48
- attr_reader :alias_tracker, :base_klass, :join_root
49
-
50
43
  def self.make_tree(associations)
51
44
  hash = {}
52
45
  walk_tree associations, hash
@@ -62,7 +55,7 @@ module ActiveRecord
62
55
  walk_tree assoc, hash
63
56
  end
64
57
  when Hash
65
- associations.each do |k,v|
58
+ associations.each do |k, v|
66
59
  cache = hash[k] ||= {}
67
60
  walk_tree v, cache
68
61
  end
@@ -71,74 +64,42 @@ module ActiveRecord
71
64
  end
72
65
  end
73
66
 
74
- # base is the base class on which operation is taking place.
75
- # associations is the list of associations which are joined using hash, symbol or array.
76
- # joins is the list of all string join commands and arel nodes.
77
- #
78
- # Example :
79
- #
80
- # class Physician < ActiveRecord::Base
81
- # has_many :appointments
82
- # has_many :patients, through: :appointments
83
- # end
84
- #
85
- # If I execute `@physician.patients.to_a` then
86
- # base # => Physician
87
- # associations # => []
88
- # joins # => [#<Arel::Nodes::InnerJoin: ...]
89
- #
90
- # However if I execute `Physician.joins(:appointments).to_a` then
91
- # base # => Physician
92
- # associations # => [:appointments]
93
- # joins # => []
94
- #
95
- def initialize(base, associations, joins)
96
- @alias_tracker = AliasTracker.create(base.connection, joins)
97
- @alias_tracker.aliased_table_for(base.table_name, base.table_name) # Updates the count for base.table_name to 1
67
+ def initialize(base, table, associations, join_type)
98
68
  tree = self.class.make_tree associations
99
- @join_root = JoinBase.new base, build(tree, base)
100
- @join_root.children.each { |child| construct_tables! @join_root, child }
69
+ @join_root = JoinBase.new(base, table, build(tree, base))
70
+ @join_type = join_type
101
71
  end
102
72
 
103
73
  def reflections
104
74
  join_root.drop(1).map!(&:reflection)
105
75
  end
106
76
 
107
- def join_constraints(outer_joins)
108
- joins = join_root.children.flat_map { |child|
109
- make_inner_joins join_root, child
110
- }
77
+ def join_constraints(joins_to_add, alias_tracker)
78
+ @alias_tracker = alias_tracker
111
79
 
112
- joins.concat outer_joins.flat_map { |oj|
80
+ construct_tables!(join_root)
81
+ joins = make_join_constraints(join_root, join_type)
82
+
83
+ joins.concat joins_to_add.flat_map { |oj|
84
+ construct_tables!(oj.join_root)
113
85
  if join_root.match? oj.join_root
114
- walk join_root, oj.join_root
86
+ walk(join_root, oj.join_root, oj.join_type)
115
87
  else
116
- oj.join_root.children.flat_map { |child|
117
- make_outer_joins oj.join_root, child
118
- }
88
+ make_join_constraints(oj.join_root, oj.join_type)
119
89
  end
120
90
  }
121
91
  end
122
92
 
123
- def aliases
124
- Aliases.new join_root.each_with_index.map { |join_part,i|
125
- columns = join_part.column_names.each_with_index.map { |column_name,j|
126
- Aliases::Column.new column_name, "t#{i}_r#{j}"
127
- }
128
- Aliases::Table.new(join_part, columns)
129
- }
130
- end
131
-
132
- def instantiate(result_set, aliases)
93
+ def instantiate(result_set, &block)
133
94
  primary_key = aliases.column_alias(join_root, join_root.primary_key)
134
95
 
135
- seen = Hash.new { |h,parent_klass|
136
- h[parent_klass] = Hash.new { |i,parent_id|
137
- i[parent_id] = Hash.new { |j,child_klass| j[child_klass] = {} }
96
+ seen = Hash.new { |i, object_id|
97
+ i[object_id] = Hash.new { |j, child_class|
98
+ j[child_class] = {}
138
99
  }
139
100
  }
140
101
 
141
- model_cache = Hash.new { |h,klass| h[klass] = {} }
102
+ model_cache = Hash.new { |h, klass| h[klass] = {} }
142
103
  parents = model_cache[join_root]
143
104
  column_aliases = aliases.column_aliases join_root
144
105
 
@@ -149,134 +110,149 @@ module ActiveRecord
149
110
  class_name: join_root.base_klass.name
150
111
  }
151
112
 
152
- message_bus.instrument('instantiation.active_record', payload) do
113
+ message_bus.instrument("instantiation.active_record", payload) do
153
114
  result_set.each { |row_hash|
154
- parent = parents[row_hash[primary_key]] ||= join_root.instantiate(row_hash, column_aliases)
155
- construct(parent, join_root, row_hash, result_set, seen, model_cache, aliases)
115
+ parent_key = primary_key ? row_hash[primary_key] : row_hash
116
+ parent = parents[parent_key] ||= join_root.instantiate(row_hash, column_aliases, &block)
117
+ construct(parent, join_root, row_hash, seen, model_cache)
156
118
  }
157
119
  end
158
120
 
159
121
  parents.values
160
122
  end
161
123
 
162
- private
163
-
164
- def make_constraints(parent, child, tables, join_type)
165
- chain = child.reflection.chain
166
- foreign_table = parent.table
167
- foreign_klass = parent.base_klass
168
- child.join_constraints(foreign_table, foreign_klass, child, join_type, tables, child.reflection.scope_chain, chain)
124
+ def apply_column_aliases(relation)
125
+ relation._select!(-> { aliases.columns })
169
126
  end
170
127
 
171
- def make_outer_joins(parent, child)
172
- tables = table_aliases_for(parent, child)
173
- join_type = Arel::Nodes::OuterJoin
174
- info = make_constraints parent, child, tables, join_type
128
+ protected
129
+ attr_reader :join_root, :join_type
175
130
 
176
- [info] + child.children.flat_map { |c| make_outer_joins(child, c) }
177
- end
131
+ private
132
+ attr_reader :alias_tracker
178
133
 
179
- def make_inner_joins(parent, child)
180
- tables = child.tables
181
- join_type = Arel::Nodes::InnerJoin
182
- info = make_constraints parent, child, tables, join_type
134
+ def aliases
135
+ @aliases ||= Aliases.new join_root.each_with_index.map { |join_part, i|
136
+ columns = join_part.column_names.each_with_index.map { |column_name, j|
137
+ Aliases::Column.new column_name, "t#{i}_r#{j}"
138
+ }
139
+ Aliases::Table.new(join_part, columns)
140
+ }
141
+ end
183
142
 
184
- [info] + child.children.flat_map { |c| make_inner_joins(child, c) }
185
- end
143
+ def construct_tables!(join_root)
144
+ join_root.each_children do |parent, child|
145
+ child.tables = table_aliases_for(parent, child)
146
+ end
147
+ end
186
148
 
187
- def table_aliases_for(parent, node)
188
- node.reflection.chain.map { |reflection|
189
- alias_tracker.aliased_table_for(
190
- reflection.table_name,
191
- table_alias_for(reflection, parent, reflection != node.reflection)
192
- )
193
- }
194
- end
149
+ def make_join_constraints(join_root, join_type)
150
+ join_root.children.flat_map do |child|
151
+ make_constraints(join_root, child, join_type)
152
+ end
153
+ end
195
154
 
196
- def construct_tables!(parent, node)
197
- node.tables = table_aliases_for(parent, node)
198
- node.children.each { |child| construct_tables! node, child }
199
- end
155
+ def make_constraints(parent, child, join_type)
156
+ foreign_table = parent.table
157
+ foreign_klass = parent.base_klass
158
+ joins = child.join_constraints(foreign_table, foreign_klass, join_type, alias_tracker)
159
+ joins.concat child.children.flat_map { |c| make_constraints(child, c, join_type) }
160
+ end
200
161
 
201
- def table_alias_for(reflection, parent, join)
202
- name = "#{reflection.plural_name}_#{parent.table_name}"
203
- name << "_join" if join
204
- name
205
- end
162
+ def table_aliases_for(parent, node)
163
+ node.reflection.chain.map { |reflection|
164
+ alias_tracker.aliased_table_for(
165
+ reflection.table_name,
166
+ table_alias_for(reflection, parent, reflection != node.reflection),
167
+ reflection.klass.type_caster
168
+ )
169
+ }
170
+ end
206
171
 
207
- def walk(left, right)
208
- intersection, missing = right.children.map { |node1|
209
- [left.children.find { |node2| node1.match? node2 }, node1]
210
- }.partition(&:first)
172
+ def table_alias_for(reflection, parent, join)
173
+ name = reflection.alias_candidate(parent.table_name)
174
+ join ? "#{name}_join" : name
175
+ end
211
176
 
212
- ojs = missing.flat_map { |_,n| make_outer_joins left, n }
213
- intersection.flat_map { |l,r| walk l, r }.concat ojs
214
- end
177
+ def walk(left, right, join_type)
178
+ intersection, missing = right.children.map { |node1|
179
+ [left.children.find { |node2| node1.match? node2 }, node1]
180
+ }.partition(&:first)
215
181
 
216
- def find_reflection(klass, name)
217
- klass._reflect_on_association(name) or
218
- raise ConfigurationError, "Association named '#{ name }' was not found on #{ klass.name }; perhaps you misspelled it?"
219
- end
182
+ joins = intersection.flat_map { |l, r| r.table = l.table; walk(l, r, join_type) }
183
+ joins.concat missing.flat_map { |_, n| make_constraints(left, n, join_type) }
184
+ end
220
185
 
221
- def build(associations, base_klass)
222
- associations.map do |name, right|
223
- reflection = find_reflection base_klass, name
224
- reflection.check_validity!
225
- reflection.check_eager_loadable!
186
+ def find_reflection(klass, name)
187
+ klass._reflect_on_association(name) ||
188
+ raise(ConfigurationError, "Can't join '#{klass.name}' to association named '#{name}'; perhaps you misspelled it?")
189
+ end
226
190
 
227
- if reflection.polymorphic?
228
- raise EagerLoadPolymorphicError.new(reflection)
229
- end
191
+ def build(associations, base_klass)
192
+ associations.map do |name, right|
193
+ reflection = find_reflection base_klass, name
194
+ reflection.check_validity!
195
+ reflection.check_eager_loadable!
230
196
 
231
- JoinAssociation.new reflection, build(right, reflection.klass)
197
+ if reflection.polymorphic?
198
+ raise EagerLoadPolymorphicError.new(reflection)
199
+ end
200
+
201
+ JoinAssociation.new(reflection, build(right, reflection.klass))
202
+ end
232
203
  end
233
- end
234
204
 
235
- def construct(ar_parent, parent, row, rs, seen, model_cache, aliases)
236
- primary_id = ar_parent.id
205
+ def construct(ar_parent, parent, row, seen, model_cache)
206
+ return if ar_parent.nil?
237
207
 
238
- parent.children.each do |node|
239
- if node.reflection.collection?
240
- other = ar_parent.association(node.reflection.name)
241
- other.loaded!
242
- else
243
- if ar_parent.association_cache.key?(node.reflection.name)
208
+ parent.children.each do |node|
209
+ if node.reflection.collection?
210
+ other = ar_parent.association(node.reflection.name)
211
+ other.loaded!
212
+ elsif ar_parent.association_cached?(node.reflection.name)
244
213
  model = ar_parent.association(node.reflection.name).target
245
- construct(model, node, row, rs, seen, model_cache, aliases)
214
+ construct(model, node, row, seen, model_cache)
246
215
  next
247
216
  end
248
- end
249
217
 
250
- key = aliases.column_alias(node, node.primary_key)
251
- id = row[key]
252
- next if id.nil?
218
+ key = aliases.column_alias(node, node.primary_key)
219
+ id = row[key]
220
+ if id.nil?
221
+ nil_association = ar_parent.association(node.reflection.name)
222
+ nil_association.loaded!
223
+ next
224
+ end
253
225
 
254
- model = seen[parent.base_klass][primary_id][node.base_klass][id]
226
+ model = seen[ar_parent.object_id][node][id]
255
227
 
256
- if model
257
- construct(model, node, row, rs, seen, model_cache, aliases)
258
- else
259
- model = construct_model(ar_parent, node, row, model_cache, id, aliases)
260
- seen[parent.base_klass][primary_id][node.base_klass][id] = model
261
- construct(model, node, row, rs, seen, model_cache, aliases)
228
+ if model
229
+ construct(model, node, row, seen, model_cache)
230
+ else
231
+ model = construct_model(ar_parent, node, row, model_cache, id)
232
+
233
+ seen[ar_parent.object_id][node][id] = model
234
+ construct(model, node, row, seen, model_cache)
235
+ end
262
236
  end
263
237
  end
264
- end
265
238
 
266
- def construct_model(record, node, row, model_cache, id, aliases)
267
- model = model_cache[node][id] ||= node.instantiate(row,
268
- aliases.column_aliases(node))
269
- other = record.association(node.reflection.name)
239
+ def construct_model(record, node, row, model_cache, id)
240
+ other = record.association(node.reflection.name)
270
241
 
271
- if node.reflection.collection?
272
- other.target.push(model)
273
- else
274
- other.target = model
275
- end
242
+ model = model_cache[node][id] ||=
243
+ node.instantiate(row, aliases.column_aliases(node)) do |m|
244
+ other.set_inverse_instance(m)
245
+ end
276
246
 
277
- other.set_inverse_instance(model)
278
- model
279
- end
247
+ if node.reflection.collection?
248
+ other.target.push(model)
249
+ else
250
+ other.target = model
251
+ end
252
+
253
+ model.readonly! if node.readonly?
254
+ model
255
+ end
280
256
  end
281
257
  end
282
258
  end