activerecord 2.3.18 → 3.2.22

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 (454) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1014 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +222 -0
  5. data/examples/performance.rb +100 -126
  6. data/examples/simple.rb +14 -0
  7. data/lib/active_record/aggregations.rb +93 -99
  8. data/lib/active_record/associations/alias_tracker.rb +76 -0
  9. data/lib/active_record/associations/association.rb +247 -0
  10. data/lib/active_record/associations/association_scope.rb +134 -0
  11. data/lib/active_record/associations/belongs_to_association.rb +54 -61
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +17 -59
  13. data/lib/active_record/associations/builder/association.rb +55 -0
  14. data/lib/active_record/associations/builder/belongs_to.rb +88 -0
  15. data/lib/active_record/associations/builder/collection_association.rb +75 -0
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +57 -0
  17. data/lib/active_record/associations/builder/has_many.rb +71 -0
  18. data/lib/active_record/associations/builder/has_one.rb +62 -0
  19. data/lib/active_record/associations/builder/singular_association.rb +32 -0
  20. data/lib/active_record/associations/collection_association.rb +580 -0
  21. data/lib/active_record/associations/collection_proxy.rb +133 -0
  22. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +39 -119
  23. data/lib/active_record/associations/has_many_association.rb +60 -79
  24. data/lib/active_record/associations/has_many_through_association.rb +127 -206
  25. data/lib/active_record/associations/has_one_association.rb +55 -114
  26. data/lib/active_record/associations/has_one_through_association.rb +25 -26
  27. data/lib/active_record/associations/join_dependency/join_association.rb +159 -0
  28. data/lib/active_record/associations/join_dependency/join_base.rb +24 -0
  29. data/lib/active_record/associations/join_dependency/join_part.rb +78 -0
  30. data/lib/active_record/associations/join_dependency.rb +214 -0
  31. data/lib/active_record/associations/join_helper.rb +55 -0
  32. data/lib/active_record/associations/preloader/association.rb +125 -0
  33. data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
  34. data/lib/active_record/associations/preloader/collection_association.rb +24 -0
  35. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +60 -0
  36. data/lib/active_record/associations/preloader/has_many.rb +17 -0
  37. data/lib/active_record/associations/preloader/has_many_through.rb +15 -0
  38. data/lib/active_record/associations/preloader/has_one.rb +23 -0
  39. data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
  40. data/lib/active_record/associations/preloader/singular_association.rb +21 -0
  41. data/lib/active_record/associations/preloader/through_association.rb +67 -0
  42. data/lib/active_record/associations/preloader.rb +181 -0
  43. data/lib/active_record/associations/singular_association.rb +64 -0
  44. data/lib/active_record/associations/through_association.rb +87 -0
  45. data/lib/active_record/associations.rb +693 -1337
  46. data/lib/active_record/attribute_assignment.rb +221 -0
  47. data/lib/active_record/attribute_methods/before_type_cast.rb +31 -0
  48. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +32 -0
  49. data/lib/active_record/attribute_methods/dirty.rb +111 -0
  50. data/lib/active_record/attribute_methods/primary_key.rb +114 -0
  51. data/lib/active_record/attribute_methods/query.rb +39 -0
  52. data/lib/active_record/attribute_methods/read.rb +136 -0
  53. data/lib/active_record/attribute_methods/serialization.rb +120 -0
  54. data/lib/active_record/attribute_methods/time_zone_conversion.rb +65 -0
  55. data/lib/active_record/attribute_methods/write.rb +70 -0
  56. data/lib/active_record/attribute_methods.rb +211 -339
  57. data/lib/active_record/autosave_association.rb +179 -149
  58. data/lib/active_record/base.rb +401 -2907
  59. data/lib/active_record/callbacks.rb +91 -176
  60. data/lib/active_record/coders/yaml_column.rb +41 -0
  61. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +236 -119
  62. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +110 -58
  63. data/lib/active_record/connection_adapters/abstract/database_limits.rb +12 -11
  64. data/lib/active_record/connection_adapters/abstract/database_statements.rb +175 -74
  65. data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -35
  66. data/lib/active_record/connection_adapters/abstract/quoting.rb +71 -21
  67. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +81 -311
  68. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +194 -78
  69. data/lib/active_record/connection_adapters/abstract_adapter.rb +130 -83
  70. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +676 -0
  71. data/lib/active_record/connection_adapters/column.rb +296 -0
  72. data/lib/active_record/connection_adapters/mysql2_adapter.rb +280 -0
  73. data/lib/active_record/connection_adapters/mysql_adapter.rb +272 -493
  74. data/lib/active_record/connection_adapters/postgresql_adapter.rb +650 -405
  75. data/lib/active_record/connection_adapters/schema_cache.rb +69 -0
  76. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +30 -9
  77. data/lib/active_record/connection_adapters/sqlite_adapter.rb +276 -147
  78. data/lib/active_record/connection_adapters/statement_pool.rb +40 -0
  79. data/lib/active_record/counter_cache.rb +123 -0
  80. data/lib/active_record/dynamic_finder_match.rb +41 -14
  81. data/lib/active_record/dynamic_matchers.rb +84 -0
  82. data/lib/active_record/dynamic_scope_match.rb +13 -15
  83. data/lib/active_record/errors.rb +195 -0
  84. data/lib/active_record/explain.rb +86 -0
  85. data/lib/active_record/explain_subscriber.rb +25 -0
  86. data/lib/active_record/fixtures/file.rb +65 -0
  87. data/lib/active_record/fixtures.rb +695 -770
  88. data/lib/active_record/identity_map.rb +162 -0
  89. data/lib/active_record/inheritance.rb +174 -0
  90. data/lib/active_record/integration.rb +60 -0
  91. data/lib/active_record/locale/en.yml +9 -27
  92. data/lib/active_record/locking/optimistic.rb +76 -73
  93. data/lib/active_record/locking/pessimistic.rb +32 -10
  94. data/lib/active_record/log_subscriber.rb +72 -0
  95. data/lib/active_record/migration/command_recorder.rb +105 -0
  96. data/lib/active_record/migration.rb +415 -205
  97. data/lib/active_record/model_schema.rb +368 -0
  98. data/lib/active_record/nested_attributes.rb +153 -63
  99. data/lib/active_record/observer.rb +27 -103
  100. data/lib/active_record/persistence.rb +376 -0
  101. data/lib/active_record/query_cache.rb +49 -8
  102. data/lib/active_record/querying.rb +58 -0
  103. data/lib/active_record/railtie.rb +131 -0
  104. data/lib/active_record/railties/console_sandbox.rb +6 -0
  105. data/lib/active_record/railties/controller_runtime.rb +49 -0
  106. data/lib/active_record/railties/databases.rake +659 -0
  107. data/lib/active_record/railties/jdbcmysql_error.rb +16 -0
  108. data/lib/active_record/readonly_attributes.rb +26 -0
  109. data/lib/active_record/reflection.rb +269 -120
  110. data/lib/active_record/relation/batches.rb +90 -0
  111. data/lib/active_record/relation/calculations.rb +372 -0
  112. data/lib/active_record/relation/delegation.rb +49 -0
  113. data/lib/active_record/relation/finder_methods.rb +402 -0
  114. data/lib/active_record/relation/predicate_builder.rb +63 -0
  115. data/lib/active_record/relation/query_methods.rb +417 -0
  116. data/lib/active_record/relation/spawn_methods.rb +180 -0
  117. data/lib/active_record/relation.rb +537 -0
  118. data/lib/active_record/result.rb +40 -0
  119. data/lib/active_record/sanitization.rb +194 -0
  120. data/lib/active_record/schema.rb +9 -6
  121. data/lib/active_record/schema_dumper.rb +55 -32
  122. data/lib/active_record/scoping/default.rb +142 -0
  123. data/lib/active_record/scoping/named.rb +200 -0
  124. data/lib/active_record/scoping.rb +152 -0
  125. data/lib/active_record/serialization.rb +8 -91
  126. data/lib/active_record/serializers/xml_serializer.rb +43 -197
  127. data/lib/active_record/session_store.rb +129 -103
  128. data/lib/active_record/store.rb +52 -0
  129. data/lib/active_record/test_case.rb +30 -23
  130. data/lib/active_record/timestamp.rb +95 -52
  131. data/lib/active_record/transactions.rb +212 -66
  132. data/lib/active_record/translation.rb +22 -0
  133. data/lib/active_record/validations/associated.rb +43 -0
  134. data/lib/active_record/validations/uniqueness.rb +180 -0
  135. data/lib/active_record/validations.rb +43 -1106
  136. data/lib/active_record/version.rb +5 -4
  137. data/lib/active_record.rb +121 -48
  138. data/lib/rails/generators/active_record/migration/migration_generator.rb +25 -0
  139. data/lib/rails/generators/active_record/migration/templates/migration.rb +34 -0
  140. data/lib/rails/generators/active_record/migration.rb +15 -0
  141. data/lib/rails/generators/active_record/model/model_generator.rb +47 -0
  142. data/lib/rails/generators/active_record/model/templates/migration.rb +15 -0
  143. data/lib/rails/generators/active_record/model/templates/model.rb +12 -0
  144. data/lib/rails/generators/active_record/model/templates/module.rb +7 -0
  145. data/lib/rails/generators/active_record/observer/observer_generator.rb +15 -0
  146. data/lib/rails/generators/active_record/observer/templates/observer.rb +4 -0
  147. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +25 -0
  148. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +12 -0
  149. data/lib/rails/generators/active_record.rb +25 -0
  150. metadata +187 -363
  151. data/CHANGELOG +0 -5904
  152. data/README +0 -351
  153. data/RUNNING_UNIT_TESTS +0 -36
  154. data/Rakefile +0 -268
  155. data/install.rb +0 -30
  156. data/lib/active_record/association_preload.rb +0 -406
  157. data/lib/active_record/associations/association_collection.rb +0 -533
  158. data/lib/active_record/associations/association_proxy.rb +0 -288
  159. data/lib/active_record/batches.rb +0 -85
  160. data/lib/active_record/calculations.rb +0 -321
  161. data/lib/active_record/dirty.rb +0 -183
  162. data/lib/active_record/named_scope.rb +0 -197
  163. data/lib/active_record/serializers/json_serializer.rb +0 -91
  164. data/lib/activerecord.rb +0 -2
  165. data/test/assets/example.log +0 -1
  166. data/test/assets/flowers.jpg +0 -0
  167. data/test/cases/aaa_create_tables_test.rb +0 -24
  168. data/test/cases/active_schema_test_mysql.rb +0 -122
  169. data/test/cases/active_schema_test_postgresql.rb +0 -24
  170. data/test/cases/adapter_test.rb +0 -144
  171. data/test/cases/aggregations_test.rb +0 -167
  172. data/test/cases/ar_schema_test.rb +0 -32
  173. data/test/cases/associations/belongs_to_associations_test.rb +0 -438
  174. data/test/cases/associations/callbacks_test.rb +0 -161
  175. data/test/cases/associations/cascaded_eager_loading_test.rb +0 -131
  176. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +0 -36
  177. data/test/cases/associations/eager_load_nested_include_test.rb +0 -131
  178. data/test/cases/associations/eager_load_nested_polymorphic_include.rb +0 -19
  179. data/test/cases/associations/eager_singularization_test.rb +0 -145
  180. data/test/cases/associations/eager_test.rb +0 -852
  181. data/test/cases/associations/extension_test.rb +0 -62
  182. data/test/cases/associations/habtm_join_table_test.rb +0 -56
  183. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +0 -827
  184. data/test/cases/associations/has_many_associations_test.rb +0 -1273
  185. data/test/cases/associations/has_many_through_associations_test.rb +0 -360
  186. data/test/cases/associations/has_one_associations_test.rb +0 -330
  187. data/test/cases/associations/has_one_through_associations_test.rb +0 -209
  188. data/test/cases/associations/inner_join_association_test.rb +0 -93
  189. data/test/cases/associations/inverse_associations_test.rb +0 -566
  190. data/test/cases/associations/join_model_test.rb +0 -712
  191. data/test/cases/associations_test.rb +0 -282
  192. data/test/cases/attribute_methods_test.rb +0 -305
  193. data/test/cases/autosave_association_test.rb +0 -1218
  194. data/test/cases/base_test.rb +0 -2166
  195. data/test/cases/batches_test.rb +0 -81
  196. data/test/cases/binary_test.rb +0 -30
  197. data/test/cases/calculations_test.rb +0 -360
  198. data/test/cases/callbacks_observers_test.rb +0 -38
  199. data/test/cases/callbacks_test.rb +0 -438
  200. data/test/cases/class_inheritable_attributes_test.rb +0 -32
  201. data/test/cases/column_alias_test.rb +0 -17
  202. data/test/cases/column_definition_test.rb +0 -70
  203. data/test/cases/connection_pool_test.rb +0 -25
  204. data/test/cases/connection_test_firebird.rb +0 -8
  205. data/test/cases/connection_test_mysql.rb +0 -65
  206. data/test/cases/copy_table_test_sqlite.rb +0 -80
  207. data/test/cases/counter_cache_test.rb +0 -84
  208. data/test/cases/database_statements_test.rb +0 -12
  209. data/test/cases/datatype_test_postgresql.rb +0 -204
  210. data/test/cases/date_time_test.rb +0 -37
  211. data/test/cases/default_test_firebird.rb +0 -16
  212. data/test/cases/defaults_test.rb +0 -111
  213. data/test/cases/deprecated_finder_test.rb +0 -30
  214. data/test/cases/dirty_test.rb +0 -316
  215. data/test/cases/finder_respond_to_test.rb +0 -76
  216. data/test/cases/finder_test.rb +0 -1098
  217. data/test/cases/fixtures_test.rb +0 -661
  218. data/test/cases/helper.rb +0 -68
  219. data/test/cases/i18n_test.rb +0 -46
  220. data/test/cases/inheritance_test.rb +0 -262
  221. data/test/cases/invalid_date_test.rb +0 -24
  222. data/test/cases/json_serialization_test.rb +0 -219
  223. data/test/cases/lifecycle_test.rb +0 -193
  224. data/test/cases/locking_test.rb +0 -350
  225. data/test/cases/method_scoping_test.rb +0 -704
  226. data/test/cases/migration_test.rb +0 -1649
  227. data/test/cases/migration_test_firebird.rb +0 -124
  228. data/test/cases/mixin_test.rb +0 -96
  229. data/test/cases/modules_test.rb +0 -109
  230. data/test/cases/multiple_db_test.rb +0 -85
  231. data/test/cases/named_scope_test.rb +0 -372
  232. data/test/cases/nested_attributes_test.rb +0 -840
  233. data/test/cases/pk_test.rb +0 -119
  234. data/test/cases/pooled_connections_test.rb +0 -103
  235. data/test/cases/query_cache_test.rb +0 -129
  236. data/test/cases/readonly_test.rb +0 -107
  237. data/test/cases/reflection_test.rb +0 -234
  238. data/test/cases/reload_models_test.rb +0 -22
  239. data/test/cases/repair_helper.rb +0 -50
  240. data/test/cases/reserved_word_test_mysql.rb +0 -176
  241. data/test/cases/sanitize_test.rb +0 -25
  242. data/test/cases/schema_authorization_test_postgresql.rb +0 -75
  243. data/test/cases/schema_dumper_test.rb +0 -211
  244. data/test/cases/schema_test_postgresql.rb +0 -178
  245. data/test/cases/serialization_test.rb +0 -47
  246. data/test/cases/sp_test_mysql.rb +0 -16
  247. data/test/cases/synonym_test_oracle.rb +0 -17
  248. data/test/cases/timestamp_test.rb +0 -75
  249. data/test/cases/transactions_test.rb +0 -543
  250. data/test/cases/unconnected_test.rb +0 -32
  251. data/test/cases/validations_i18n_test.rb +0 -925
  252. data/test/cases/validations_test.rb +0 -1684
  253. data/test/cases/xml_serialization_test.rb +0 -240
  254. data/test/cases/yaml_serialization_test.rb +0 -11
  255. data/test/config.rb +0 -5
  256. data/test/connections/jdbc_jdbcderby/connection.rb +0 -18
  257. data/test/connections/jdbc_jdbch2/connection.rb +0 -18
  258. data/test/connections/jdbc_jdbchsqldb/connection.rb +0 -18
  259. data/test/connections/jdbc_jdbcmysql/connection.rb +0 -26
  260. data/test/connections/jdbc_jdbcpostgresql/connection.rb +0 -26
  261. data/test/connections/jdbc_jdbcsqlite3/connection.rb +0 -25
  262. data/test/connections/native_db2/connection.rb +0 -25
  263. data/test/connections/native_firebird/connection.rb +0 -26
  264. data/test/connections/native_frontbase/connection.rb +0 -27
  265. data/test/connections/native_mysql/connection.rb +0 -25
  266. data/test/connections/native_openbase/connection.rb +0 -21
  267. data/test/connections/native_oracle/connection.rb +0 -27
  268. data/test/connections/native_postgresql/connection.rb +0 -21
  269. data/test/connections/native_sqlite/connection.rb +0 -25
  270. data/test/connections/native_sqlite3/connection.rb +0 -25
  271. data/test/connections/native_sqlite3/in_memory_connection.rb +0 -18
  272. data/test/connections/native_sybase/connection.rb +0 -23
  273. data/test/fixtures/accounts.yml +0 -29
  274. data/test/fixtures/all/developers.yml +0 -0
  275. data/test/fixtures/all/people.csv +0 -0
  276. data/test/fixtures/all/tasks.yml +0 -0
  277. data/test/fixtures/author_addresses.yml +0 -5
  278. data/test/fixtures/author_favorites.yml +0 -4
  279. data/test/fixtures/authors.yml +0 -9
  280. data/test/fixtures/binaries.yml +0 -132
  281. data/test/fixtures/books.yml +0 -7
  282. data/test/fixtures/categories/special_categories.yml +0 -9
  283. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +0 -4
  284. data/test/fixtures/categories.yml +0 -14
  285. data/test/fixtures/categories_ordered.yml +0 -7
  286. data/test/fixtures/categories_posts.yml +0 -23
  287. data/test/fixtures/categorizations.yml +0 -17
  288. data/test/fixtures/clubs.yml +0 -6
  289. data/test/fixtures/comments.yml +0 -59
  290. data/test/fixtures/companies.yml +0 -56
  291. data/test/fixtures/computers.yml +0 -4
  292. data/test/fixtures/courses.yml +0 -7
  293. data/test/fixtures/customers.yml +0 -26
  294. data/test/fixtures/developers.yml +0 -21
  295. data/test/fixtures/developers_projects.yml +0 -17
  296. data/test/fixtures/edges.yml +0 -6
  297. data/test/fixtures/entrants.yml +0 -14
  298. data/test/fixtures/faces.yml +0 -11
  299. data/test/fixtures/fk_test_has_fk.yml +0 -3
  300. data/test/fixtures/fk_test_has_pk.yml +0 -2
  301. data/test/fixtures/funny_jokes.yml +0 -10
  302. data/test/fixtures/interests.yml +0 -33
  303. data/test/fixtures/items.yml +0 -4
  304. data/test/fixtures/jobs.yml +0 -7
  305. data/test/fixtures/legacy_things.yml +0 -3
  306. data/test/fixtures/mateys.yml +0 -4
  307. data/test/fixtures/member_types.yml +0 -6
  308. data/test/fixtures/members.yml +0 -6
  309. data/test/fixtures/memberships.yml +0 -20
  310. data/test/fixtures/men.yml +0 -5
  311. data/test/fixtures/minimalistics.yml +0 -2
  312. data/test/fixtures/mixed_case_monkeys.yml +0 -6
  313. data/test/fixtures/mixins.yml +0 -29
  314. data/test/fixtures/movies.yml +0 -7
  315. data/test/fixtures/naked/csv/accounts.csv +0 -1
  316. data/test/fixtures/naked/yml/accounts.yml +0 -1
  317. data/test/fixtures/naked/yml/companies.yml +0 -1
  318. data/test/fixtures/naked/yml/courses.yml +0 -1
  319. data/test/fixtures/organizations.yml +0 -5
  320. data/test/fixtures/owners.yml +0 -7
  321. data/test/fixtures/parrots.yml +0 -27
  322. data/test/fixtures/parrots_pirates.yml +0 -7
  323. data/test/fixtures/people.yml +0 -15
  324. data/test/fixtures/pets.yml +0 -14
  325. data/test/fixtures/pirates.yml +0 -9
  326. data/test/fixtures/polymorphic_designs.yml +0 -19
  327. data/test/fixtures/polymorphic_prices.yml +0 -19
  328. data/test/fixtures/posts.yml +0 -52
  329. data/test/fixtures/price_estimates.yml +0 -7
  330. data/test/fixtures/projects.yml +0 -7
  331. data/test/fixtures/readers.yml +0 -9
  332. data/test/fixtures/references.yml +0 -17
  333. data/test/fixtures/reserved_words/distinct.yml +0 -5
  334. data/test/fixtures/reserved_words/distincts_selects.yml +0 -11
  335. data/test/fixtures/reserved_words/group.yml +0 -14
  336. data/test/fixtures/reserved_words/select.yml +0 -8
  337. data/test/fixtures/reserved_words/values.yml +0 -7
  338. data/test/fixtures/ships.yml +0 -5
  339. data/test/fixtures/sponsors.yml +0 -9
  340. data/test/fixtures/subscribers.yml +0 -7
  341. data/test/fixtures/subscriptions.yml +0 -12
  342. data/test/fixtures/taggings.yml +0 -28
  343. data/test/fixtures/tags.yml +0 -7
  344. data/test/fixtures/tasks.yml +0 -7
  345. data/test/fixtures/tees.yml +0 -4
  346. data/test/fixtures/ties.yml +0 -4
  347. data/test/fixtures/topics.yml +0 -42
  348. data/test/fixtures/toys.yml +0 -4
  349. data/test/fixtures/treasures.yml +0 -10
  350. data/test/fixtures/vertices.yml +0 -4
  351. data/test/fixtures/warehouse-things.yml +0 -3
  352. data/test/fixtures/zines.yml +0 -5
  353. data/test/migrations/broken/100_migration_that_raises_exception.rb +0 -10
  354. data/test/migrations/decimal/1_give_me_big_numbers.rb +0 -15
  355. data/test/migrations/duplicate/1_people_have_last_names.rb +0 -9
  356. data/test/migrations/duplicate/2_we_need_reminders.rb +0 -12
  357. data/test/migrations/duplicate/3_foo.rb +0 -7
  358. data/test/migrations/duplicate/3_innocent_jointable.rb +0 -12
  359. data/test/migrations/duplicate_names/20080507052938_chunky.rb +0 -7
  360. data/test/migrations/duplicate_names/20080507053028_chunky.rb +0 -7
  361. data/test/migrations/interleaved/pass_1/3_innocent_jointable.rb +0 -12
  362. data/test/migrations/interleaved/pass_2/1_people_have_last_names.rb +0 -9
  363. data/test/migrations/interleaved/pass_2/3_innocent_jointable.rb +0 -12
  364. data/test/migrations/interleaved/pass_3/1_people_have_last_names.rb +0 -9
  365. data/test/migrations/interleaved/pass_3/2_i_raise_on_down.rb +0 -8
  366. data/test/migrations/interleaved/pass_3/3_innocent_jointable.rb +0 -12
  367. data/test/migrations/missing/1000_people_have_middle_names.rb +0 -9
  368. data/test/migrations/missing/1_people_have_last_names.rb +0 -9
  369. data/test/migrations/missing/3_we_need_reminders.rb +0 -12
  370. data/test/migrations/missing/4_innocent_jointable.rb +0 -12
  371. data/test/migrations/valid/1_people_have_last_names.rb +0 -9
  372. data/test/migrations/valid/2_we_need_reminders.rb +0 -12
  373. data/test/migrations/valid/3_innocent_jointable.rb +0 -12
  374. data/test/models/author.rb +0 -151
  375. data/test/models/auto_id.rb +0 -4
  376. data/test/models/binary.rb +0 -2
  377. data/test/models/bird.rb +0 -9
  378. data/test/models/book.rb +0 -4
  379. data/test/models/categorization.rb +0 -5
  380. data/test/models/category.rb +0 -34
  381. data/test/models/citation.rb +0 -6
  382. data/test/models/club.rb +0 -13
  383. data/test/models/column_name.rb +0 -3
  384. data/test/models/comment.rb +0 -29
  385. data/test/models/company.rb +0 -173
  386. data/test/models/company_in_module.rb +0 -78
  387. data/test/models/computer.rb +0 -3
  388. data/test/models/contact.rb +0 -16
  389. data/test/models/contract.rb +0 -5
  390. data/test/models/course.rb +0 -3
  391. data/test/models/customer.rb +0 -73
  392. data/test/models/default.rb +0 -2
  393. data/test/models/developer.rb +0 -101
  394. data/test/models/edge.rb +0 -5
  395. data/test/models/entrant.rb +0 -3
  396. data/test/models/essay.rb +0 -3
  397. data/test/models/event.rb +0 -3
  398. data/test/models/event_author.rb +0 -8
  399. data/test/models/face.rb +0 -7
  400. data/test/models/guid.rb +0 -2
  401. data/test/models/interest.rb +0 -5
  402. data/test/models/invoice.rb +0 -4
  403. data/test/models/item.rb +0 -7
  404. data/test/models/job.rb +0 -5
  405. data/test/models/joke.rb +0 -3
  406. data/test/models/keyboard.rb +0 -3
  407. data/test/models/legacy_thing.rb +0 -3
  408. data/test/models/line_item.rb +0 -3
  409. data/test/models/man.rb +0 -9
  410. data/test/models/matey.rb +0 -4
  411. data/test/models/member.rb +0 -12
  412. data/test/models/member_detail.rb +0 -5
  413. data/test/models/member_type.rb +0 -3
  414. data/test/models/membership.rb +0 -9
  415. data/test/models/minimalistic.rb +0 -2
  416. data/test/models/mixed_case_monkey.rb +0 -3
  417. data/test/models/movie.rb +0 -5
  418. data/test/models/order.rb +0 -4
  419. data/test/models/organization.rb +0 -6
  420. data/test/models/owner.rb +0 -5
  421. data/test/models/parrot.rb +0 -22
  422. data/test/models/person.rb +0 -16
  423. data/test/models/pet.rb +0 -5
  424. data/test/models/pirate.rb +0 -80
  425. data/test/models/polymorphic_design.rb +0 -3
  426. data/test/models/polymorphic_price.rb +0 -3
  427. data/test/models/post.rb +0 -102
  428. data/test/models/price_estimate.rb +0 -3
  429. data/test/models/project.rb +0 -30
  430. data/test/models/reader.rb +0 -4
  431. data/test/models/reference.rb +0 -4
  432. data/test/models/reply.rb +0 -46
  433. data/test/models/ship.rb +0 -19
  434. data/test/models/ship_part.rb +0 -7
  435. data/test/models/sponsor.rb +0 -4
  436. data/test/models/subject.rb +0 -4
  437. data/test/models/subscriber.rb +0 -8
  438. data/test/models/subscription.rb +0 -4
  439. data/test/models/tag.rb +0 -7
  440. data/test/models/tagging.rb +0 -10
  441. data/test/models/task.rb +0 -3
  442. data/test/models/tee.rb +0 -4
  443. data/test/models/tie.rb +0 -4
  444. data/test/models/topic.rb +0 -80
  445. data/test/models/toy.rb +0 -6
  446. data/test/models/treasure.rb +0 -8
  447. data/test/models/vertex.rb +0 -9
  448. data/test/models/warehouse_thing.rb +0 -5
  449. data/test/models/zine.rb +0 -3
  450. data/test/schema/mysql_specific_schema.rb +0 -31
  451. data/test/schema/postgresql_specific_schema.rb +0 -114
  452. data/test/schema/schema.rb +0 -550
  453. data/test/schema/schema2.rb +0 -6
  454. data/test/schema/sqlite_specific_schema.rb +0 -25
@@ -0,0 +1,159 @@
1
+ module ActiveRecord
2
+ module Associations
3
+ class JoinDependency # :nodoc:
4
+ class JoinAssociation < JoinPart # :nodoc:
5
+ include JoinHelper
6
+
7
+ # The reflection of the association represented
8
+ attr_reader :reflection
9
+
10
+ # The JoinDependency object which this JoinAssociation exists within. This is mainly
11
+ # relevant for generating aliases which do not conflict with other joins which are
12
+ # part of the query.
13
+ attr_reader :join_dependency
14
+
15
+ # A JoinBase instance representing the active record we are joining onto.
16
+ # (So in Author.has_many :posts, the Author would be that base record.)
17
+ attr_reader :parent
18
+
19
+ # What type of join will be generated, either Arel::InnerJoin (default) or Arel::OuterJoin
20
+ attr_accessor :join_type
21
+
22
+ # These implement abstract methods from the superclass
23
+ attr_reader :aliased_prefix
24
+
25
+ attr_reader :tables
26
+
27
+ delegate :options, :through_reflection, :source_reflection, :chain, :to => :reflection
28
+ delegate :table, :table_name, :to => :parent, :prefix => :parent
29
+ delegate :alias_tracker, :to => :join_dependency
30
+
31
+ alias :alias_suffix :parent_table_name
32
+
33
+ def initialize(reflection, join_dependency, parent = nil)
34
+ reflection.check_validity!
35
+
36
+ if reflection.options[:polymorphic]
37
+ raise EagerLoadPolymorphicError.new(reflection)
38
+ end
39
+
40
+ super(reflection.klass)
41
+
42
+ @reflection = reflection
43
+ @join_dependency = join_dependency
44
+ @parent = parent
45
+ @join_type = Arel::InnerJoin
46
+ @aliased_prefix = "t#{ join_dependency.join_parts.size }"
47
+ @tables = construct_tables.reverse
48
+ end
49
+
50
+ def ==(other)
51
+ other.class == self.class &&
52
+ other.reflection == reflection &&
53
+ other.parent == parent
54
+ end
55
+
56
+ def find_parent_in(other_join_dependency)
57
+ other_join_dependency.join_parts.detect do |join_part|
58
+ case parent
59
+ when JoinBase
60
+ parent.active_record == join_part.active_record
61
+ else
62
+ parent == join_part
63
+ end
64
+ end
65
+ end
66
+
67
+ def join_to(relation)
68
+ tables = @tables.dup
69
+ foreign_table = parent_table
70
+ foreign_klass = parent.active_record
71
+
72
+ # The chain starts with the target table, but we want to end with it here (makes
73
+ # more sense in this context), so we reverse
74
+ chain.reverse.each_with_index do |reflection, i|
75
+ table = tables.shift
76
+
77
+ case reflection.source_macro
78
+ when :belongs_to
79
+ key = reflection.association_primary_key
80
+ foreign_key = reflection.foreign_key
81
+ when :has_and_belongs_to_many
82
+ # Join the join table first...
83
+ relation.from(join(
84
+ table,
85
+ table[reflection.foreign_key].
86
+ eq(foreign_table[reflection.active_record_primary_key])
87
+ ))
88
+
89
+ foreign_table, table = table, tables.shift
90
+
91
+ key = reflection.association_primary_key
92
+ foreign_key = reflection.association_foreign_key
93
+ else
94
+ key = reflection.foreign_key
95
+ foreign_key = reflection.active_record_primary_key
96
+ end
97
+
98
+ constraint = build_constraint(reflection, table, key, foreign_table, foreign_key)
99
+
100
+ conditions = self.conditions[i].dup
101
+ conditions << { reflection.type => foreign_klass.base_class.name } if reflection.type
102
+
103
+ unless conditions.empty?
104
+ constraint = constraint.and(sanitize(conditions, table))
105
+ end
106
+
107
+ relation.from(join(table, constraint))
108
+
109
+ # The current table in this iteration becomes the foreign table in the next
110
+ foreign_table, foreign_klass = table, reflection.klass
111
+ end
112
+
113
+ relation
114
+ end
115
+
116
+ def build_constraint(reflection, table, key, foreign_table, foreign_key)
117
+ constraint = table[key].eq(foreign_table[foreign_key])
118
+
119
+ if reflection.klass.finder_needs_type_condition?
120
+ constraint = table.create_and([
121
+ constraint,
122
+ reflection.klass.send(:type_condition, table)
123
+ ])
124
+ end
125
+
126
+ constraint
127
+ end
128
+
129
+ def join_relation(joining_relation)
130
+ self.join_type = Arel::OuterJoin
131
+ joining_relation.joins(self)
132
+ end
133
+
134
+ def table
135
+ tables.last
136
+ end
137
+
138
+ def aliased_table_name
139
+ table.table_alias || table.name
140
+ end
141
+
142
+ def conditions
143
+ @conditions ||= reflection.conditions.reverse
144
+ end
145
+
146
+ private
147
+
148
+ def interpolate(conditions)
149
+ if conditions.respond_to?(:to_proc)
150
+ instance_eval(&conditions)
151
+ else
152
+ conditions
153
+ end
154
+ end
155
+
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,24 @@
1
+ module ActiveRecord
2
+ module Associations
3
+ class JoinDependency # :nodoc:
4
+ class JoinBase < JoinPart # :nodoc:
5
+ def ==(other)
6
+ other.class == self.class &&
7
+ other.active_record == active_record
8
+ end
9
+
10
+ def aliased_prefix
11
+ "t0"
12
+ end
13
+
14
+ def table
15
+ Arel::Table.new(table_name, arel_engine)
16
+ end
17
+
18
+ def aliased_table_name
19
+ active_record.table_name
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,78 @@
1
+ module ActiveRecord
2
+ module Associations
3
+ class JoinDependency # :nodoc:
4
+ # A JoinPart represents a part of a JoinDependency. It is an abstract class, inherited
5
+ # by JoinBase and JoinAssociation. A JoinBase represents the Active Record which
6
+ # everything else is being joined onto. A JoinAssociation represents an association which
7
+ # is joining to the base. A JoinAssociation may result in more than one actual join
8
+ # operations (for example a has_and_belongs_to_many JoinAssociation would result in
9
+ # two; one for the join table and one for the target table).
10
+ class JoinPart # :nodoc:
11
+ # The Active Record class which this join part is associated 'about'; for a JoinBase
12
+ # this is the actual base model, for a JoinAssociation this is the target model of the
13
+ # association.
14
+ attr_reader :active_record
15
+
16
+ delegate :table_name, :column_names, :primary_key, :reflections, :arel_engine, :to => :active_record
17
+
18
+ def initialize(active_record)
19
+ @active_record = active_record
20
+ @cached_record = {}
21
+ @column_names_with_alias = nil
22
+ end
23
+
24
+ def aliased_table
25
+ Arel::Nodes::TableAlias.new table, aliased_table_name
26
+ end
27
+
28
+ def ==(other)
29
+ raise NotImplementedError
30
+ end
31
+
32
+ # An Arel::Table for the active_record
33
+ def table
34
+ raise NotImplementedError
35
+ end
36
+
37
+ # The prefix to be used when aliasing columns in the active_record's table
38
+ def aliased_prefix
39
+ raise NotImplementedError
40
+ end
41
+
42
+ # The alias for the active_record's table
43
+ def aliased_table_name
44
+ raise NotImplementedError
45
+ end
46
+
47
+ # The alias for the primary key of the active_record's table
48
+ def aliased_primary_key
49
+ "#{aliased_prefix}_r0"
50
+ end
51
+
52
+ # An array of [column_name, alias] pairs for the table
53
+ def column_names_with_alias
54
+ unless @column_names_with_alias
55
+ @column_names_with_alias = []
56
+
57
+ ([primary_key] + (column_names - [primary_key])).each_with_index do |column_name, i|
58
+ @column_names_with_alias << [column_name, "#{aliased_prefix}_r#{i}"]
59
+ end
60
+ end
61
+ @column_names_with_alias
62
+ end
63
+
64
+ def extract_record(row)
65
+ Hash[column_names_with_alias.map{|cn, an| [cn, row[an]]}]
66
+ end
67
+
68
+ def record_id(row)
69
+ row[aliased_primary_key]
70
+ end
71
+
72
+ def instantiate(row)
73
+ @cached_record[record_id(row)] ||= active_record.send(:instantiate, extract_record(row))
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,214 @@
1
+ module ActiveRecord
2
+ module Associations
3
+ class JoinDependency # :nodoc:
4
+ autoload :JoinPart, 'active_record/associations/join_dependency/join_part'
5
+ autoload :JoinBase, 'active_record/associations/join_dependency/join_base'
6
+ autoload :JoinAssociation, 'active_record/associations/join_dependency/join_association'
7
+
8
+ attr_reader :join_parts, :reflections, :alias_tracker, :active_record
9
+
10
+ def initialize(base, associations, joins)
11
+ @active_record = base
12
+ @table_joins = joins
13
+ @join_parts = [JoinBase.new(base)]
14
+ @associations = {}
15
+ @reflections = []
16
+ @alias_tracker = AliasTracker.new(base.connection, joins)
17
+ @alias_tracker.aliased_name_for(base.table_name) # Updates the count for base.table_name to 1
18
+ build(associations)
19
+ end
20
+
21
+ def graft(*associations)
22
+ associations.each do |association|
23
+ join_associations.detect {|a| association == a} ||
24
+ build(association.reflection.name, association.find_parent_in(self) || join_base, association.join_type)
25
+ end
26
+ self
27
+ end
28
+
29
+ def join_associations
30
+ join_parts.last(join_parts.length - 1)
31
+ end
32
+
33
+ def join_base
34
+ join_parts.first
35
+ end
36
+
37
+ def columns
38
+ join_parts.collect { |join_part|
39
+ table = join_part.aliased_table
40
+ join_part.column_names_with_alias.collect{ |column_name, aliased_name|
41
+ table[column_name].as Arel.sql(aliased_name)
42
+ }
43
+ }.flatten
44
+ end
45
+
46
+ def instantiate(rows)
47
+ primary_key = join_base.aliased_primary_key
48
+ parents = {}
49
+
50
+ records = rows.map { |model|
51
+ primary_id = model[primary_key]
52
+ parent = parents[primary_id] ||= join_base.instantiate(model)
53
+ construct(parent, @associations, join_associations, model)
54
+ parent
55
+ }.uniq
56
+
57
+ remove_duplicate_results!(active_record, records, @associations)
58
+ records
59
+ end
60
+
61
+ def remove_duplicate_results!(base, records, associations)
62
+ case associations
63
+ when Symbol, String
64
+ reflection = base.reflections[associations]
65
+ remove_uniq_by_reflection(reflection, records)
66
+ when Array
67
+ associations.each do |association|
68
+ remove_duplicate_results!(base, records, association)
69
+ end
70
+ when Hash
71
+ associations.keys.each do |name|
72
+ reflection = base.reflections[name]
73
+ remove_uniq_by_reflection(reflection, records)
74
+
75
+ parent_records = []
76
+ records.each do |record|
77
+ if descendant = record.send(reflection.name)
78
+ if reflection.collection?
79
+ parent_records.concat descendant.target.uniq
80
+ else
81
+ parent_records << descendant
82
+ end
83
+ end
84
+ end
85
+
86
+ remove_duplicate_results!(reflection.klass, parent_records, associations[name]) unless parent_records.empty?
87
+ end
88
+ end
89
+ end
90
+
91
+ protected
92
+
93
+ def cache_joined_association(association)
94
+ associations = []
95
+ parent = association.parent
96
+ while parent != join_base
97
+ associations.unshift(parent.reflection.name)
98
+ parent = parent.parent
99
+ end
100
+ ref = @associations
101
+ associations.each do |key|
102
+ ref = ref[key]
103
+ end
104
+ ref[association.reflection.name] ||= {}
105
+ end
106
+
107
+ def build(associations, parent = nil, join_type = Arel::InnerJoin)
108
+ parent ||= join_parts.last
109
+ case associations
110
+ when Symbol, String
111
+ reflection = parent.reflections[associations.to_s.intern] or
112
+ raise ConfigurationError, "Association named '#{ associations }' was not found on #{parent.active_record.name}; perhaps you misspelled it?"
113
+ unless join_association = find_join_association(reflection, parent)
114
+ @reflections << reflection
115
+ join_association = build_join_association(reflection, parent)
116
+ join_association.join_type = join_type
117
+ @join_parts << join_association
118
+ cache_joined_association(join_association)
119
+ end
120
+ join_association
121
+ when Array
122
+ associations.each do |association|
123
+ build(association, parent, join_type)
124
+ end
125
+ when Hash
126
+ associations.keys.sort_by { |a| a.to_s }.each do |name|
127
+ join_association = build(name, parent, join_type)
128
+ build(associations[name], join_association, join_type)
129
+ end
130
+ else
131
+ raise ConfigurationError, associations.inspect
132
+ end
133
+ end
134
+
135
+ def find_join_association(name_or_reflection, parent)
136
+ if String === name_or_reflection
137
+ name_or_reflection = name_or_reflection.to_sym
138
+ end
139
+
140
+ join_associations.detect { |j|
141
+ j.reflection == name_or_reflection && j.parent == parent
142
+ }
143
+ end
144
+
145
+ def remove_uniq_by_reflection(reflection, records)
146
+ if reflection && reflection.collection?
147
+ records.each { |record| record.send(reflection.name).target.uniq! }
148
+ end
149
+ end
150
+
151
+ def build_join_association(reflection, parent)
152
+ JoinAssociation.new(reflection, self, parent)
153
+ end
154
+
155
+ def construct(parent, associations, join_parts, row)
156
+ case associations
157
+ when Symbol, String
158
+ name = associations.to_s
159
+
160
+ join_part = join_parts.detect { |j|
161
+ j.reflection.name.to_s == name &&
162
+ j.parent_table_name == parent.class.table_name }
163
+
164
+ raise(ConfigurationError, "No such association") unless join_part
165
+
166
+ join_parts.delete(join_part)
167
+ construct_association(parent, join_part, row)
168
+ when Array
169
+ associations.each do |association|
170
+ construct(parent, association, join_parts, row)
171
+ end
172
+ when Hash
173
+ associations.sort_by { |k,_| k.to_s }.each do |association_name, assoc|
174
+ association = construct(parent, association_name, join_parts, row)
175
+ construct(association, assoc, join_parts, row) if association
176
+ end
177
+ else
178
+ raise ConfigurationError, associations.inspect
179
+ end
180
+ end
181
+
182
+ def construct_association(record, join_part, row)
183
+ return if record.id.to_s != join_part.parent.record_id(row).to_s
184
+
185
+ macro = join_part.reflection.macro
186
+ if macro == :has_one
187
+ return record.association(join_part.reflection.name).target if record.association_cache.key?(join_part.reflection.name)
188
+ association = join_part.instantiate(row) unless row[join_part.aliased_primary_key].nil?
189
+ set_target_and_inverse(join_part, association, record)
190
+ else
191
+ association = join_part.instantiate(row) unless row[join_part.aliased_primary_key].nil?
192
+ case macro
193
+ when :has_many, :has_and_belongs_to_many
194
+ other = record.association(join_part.reflection.name)
195
+ other.loaded!
196
+ other.target.push(association) if association
197
+ other.set_inverse_instance(association)
198
+ when :belongs_to
199
+ set_target_and_inverse(join_part, association, record)
200
+ else
201
+ raise ConfigurationError, "unknown macro: #{join_part.reflection.macro}"
202
+ end
203
+ end
204
+ association
205
+ end
206
+
207
+ def set_target_and_inverse(join_part, association, record)
208
+ other = record.association(join_part.reflection.name)
209
+ other.target = association
210
+ other.set_inverse_instance(association)
211
+ end
212
+ end
213
+ end
214
+ end
@@ -0,0 +1,55 @@
1
+ module ActiveRecord
2
+ module Associations
3
+ # Helper class module which gets mixed into JoinDependency::JoinAssociation and AssociationScope
4
+ module JoinHelper #:nodoc:
5
+
6
+ def join_type
7
+ Arel::InnerJoin
8
+ end
9
+
10
+ private
11
+
12
+ def construct_tables
13
+ tables = []
14
+ chain.each do |reflection|
15
+ tables << alias_tracker.aliased_table_for(
16
+ table_name_for(reflection),
17
+ table_alias_for(reflection, reflection != self.reflection)
18
+ )
19
+
20
+ if reflection.source_macro == :has_and_belongs_to_many
21
+ tables << alias_tracker.aliased_table_for(
22
+ (reflection.source_reflection || reflection).options[:join_table],
23
+ table_alias_for(reflection, true)
24
+ )
25
+ end
26
+ end
27
+ tables
28
+ end
29
+
30
+ def table_name_for(reflection)
31
+ reflection.table_name
32
+ end
33
+
34
+ def table_alias_for(reflection, join = false)
35
+ name = "#{reflection.plural_name}_#{alias_suffix}"
36
+ name << "_join" if join
37
+ name
38
+ end
39
+
40
+ def join(table, constraint)
41
+ table.create_join(table, table.create_on(constraint), join_type)
42
+ end
43
+
44
+ def sanitize(conditions, table)
45
+ conditions = conditions.map do |condition|
46
+ condition = active_record.send(:sanitize_sql, interpolate(condition), table.table_alias || table.name)
47
+ condition = Arel.sql(condition) unless condition.is_a?(Arel::Node)
48
+ condition
49
+ end
50
+
51
+ conditions.length == 1 ? conditions.first : Arel::Nodes::And.new(conditions)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,125 @@
1
+ module ActiveRecord
2
+ module Associations
3
+ class Preloader
4
+ class Association #:nodoc:
5
+ attr_reader :owners, :reflection, :preload_options, :model, :klass
6
+
7
+ def initialize(klass, owners, reflection, preload_options)
8
+ @klass = klass
9
+ @owners = owners
10
+ @reflection = reflection
11
+ @preload_options = preload_options || {}
12
+ @model = owners.first && owners.first.class
13
+ @scoped = nil
14
+ @owners_by_key = nil
15
+ end
16
+
17
+ def run
18
+ unless owners.first.association(reflection.name).loaded?
19
+ preload
20
+ end
21
+ end
22
+
23
+ def preload
24
+ raise NotImplementedError
25
+ end
26
+
27
+ def scoped
28
+ @scoped ||= build_scope
29
+ end
30
+
31
+ def records_for(ids)
32
+ scoped.where(association_key.in(ids))
33
+ end
34
+
35
+ def table
36
+ klass.arel_table
37
+ end
38
+
39
+ # The name of the key on the associated records
40
+ def association_key_name
41
+ raise NotImplementedError
42
+ end
43
+
44
+ # This is overridden by HABTM as the condition should be on the foreign_key column in
45
+ # the join table
46
+ def association_key
47
+ table[association_key_name]
48
+ end
49
+
50
+ # The name of the key on the model which declares the association
51
+ def owner_key_name
52
+ raise NotImplementedError
53
+ end
54
+
55
+ # We're converting to a string here because postgres will return the aliased association
56
+ # key in a habtm as a string (for whatever reason)
57
+ def owners_by_key
58
+ @owners_by_key ||= owners.group_by do |owner|
59
+ key = owner[owner_key_name]
60
+ key && key.to_s
61
+ end
62
+ end
63
+
64
+ def options
65
+ reflection.options
66
+ end
67
+
68
+ private
69
+
70
+ def associated_records_by_owner
71
+ owners_map = owners_by_key
72
+ owner_keys = owners_map.keys.compact
73
+
74
+ if klass.nil? || owner_keys.empty?
75
+ records = []
76
+ else
77
+ # Some databases impose a limit on the number of ids in a list (in Oracle it's 1000)
78
+ # Make several smaller queries if necessary or make one query if the adapter supports it
79
+ sliced = owner_keys.each_slice(model.connection.in_clause_length || owner_keys.size)
80
+ records = sliced.map { |slice| records_for(slice) }.flatten
81
+ end
82
+
83
+ # Each record may have multiple owners, and vice-versa
84
+ records_by_owner = Hash[owners.map { |owner| [owner, []] }]
85
+ records.each do |record|
86
+ owner_key = record[association_key_name].to_s
87
+
88
+ owners_map[owner_key].each do |owner|
89
+ records_by_owner[owner] << record
90
+ end
91
+ end
92
+ records_by_owner
93
+ end
94
+
95
+ def build_scope
96
+ scope = klass.scoped
97
+
98
+ scope = scope.where(process_conditions(options[:conditions]))
99
+ scope = scope.where(process_conditions(preload_options[:conditions]))
100
+
101
+ scope = scope.select(preload_options[:select] || options[:select] || table[Arel.star])
102
+ scope = scope.includes(preload_options[:include] || options[:include])
103
+
104
+ if options[:as]
105
+ scope = scope.where(
106
+ klass.table_name => {
107
+ reflection.type => model.base_class.sti_name
108
+ }
109
+ )
110
+ end
111
+
112
+ scope
113
+ end
114
+
115
+ def process_conditions(conditions)
116
+ if conditions.respond_to?(:to_proc)
117
+ conditions = klass.send(:instance_eval, &conditions)
118
+ end
119
+
120
+ conditions
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,17 @@
1
+ module ActiveRecord
2
+ module Associations
3
+ class Preloader
4
+ class BelongsTo < SingularAssociation #:nodoc:
5
+
6
+ def association_key_name
7
+ reflection.options[:primary_key] || klass && klass.primary_key
8
+ end
9
+
10
+ def owner_key_name
11
+ reflection.foreign_key
12
+ end
13
+
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,24 @@
1
+ module ActiveRecord
2
+ module Associations
3
+ class Preloader
4
+ class CollectionAssociation < Association #:nodoc:
5
+
6
+ private
7
+
8
+ def build_scope
9
+ super.order(preload_options[:order] || options[:order])
10
+ end
11
+
12
+ def preload
13
+ associated_records_by_owner.each do |owner, records|
14
+ association = owner.association(reflection.name)
15
+ association.loaded!
16
+ association.target.concat(records)
17
+ records.each { |record| association.set_inverse_instance(record) }
18
+ end
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+ end