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
@@ -1,13 +1,16 @@
1
+ require 'active_support/core_ext/array/wrap'
2
+
1
3
  module ActiveRecord
2
- # AutosaveAssociation is a module that takes care of automatically saving
3
- # your associations when the parent is saved. In addition to saving, it
4
- # also destroys any associations that were marked for destruction.
5
- # (See mark_for_destruction and marked_for_destruction?)
4
+ # = Active Record Autosave Association
5
+ #
6
+ # +AutosaveAssociation+ is a module that takes care of automatically saving
7
+ # associated records when their parent is saved. In addition to saving, it
8
+ # also destroys any associated records that were marked for destruction.
9
+ # (See +mark_for_destruction+ and <tt>marked_for_destruction?</tt>).
6
10
  #
7
11
  # Saving of the parent, its associations, and the destruction of marked
8
- # associations, all happen inside 1 transaction. This should never leave the
9
- # database in an inconsistent state after, for instance, mass assigning
10
- # attributes and saving them.
12
+ # associations, all happen inside a transaction. This should never leave the
13
+ # database in an inconsistent state.
11
14
  #
12
15
  # If validations for any of the associations fail, their error messages will
13
16
  # be applied to the parent.
@@ -15,9 +18,25 @@ module ActiveRecord
15
18
  # Note that it also means that associations marked for destruction won't
16
19
  # be destroyed directly. They will however still be marked for destruction.
17
20
  #
18
- # === One-to-one Example
21
+ # Note that <tt>:autosave => false</tt> is not same as not declaring <tt>:autosave</tt>.
22
+ # When the <tt>:autosave</tt> option is not present new associations are saved.
23
+ #
24
+ # == Validation
25
+ #
26
+ # Children records are validated unless <tt>:validate</tt> is +false+.
19
27
  #
20
- # Consider a Post model with one Author:
28
+ # == Callbacks
29
+ #
30
+ # Association with autosave option defines several callbacks on your
31
+ # model (before_save, after_create, after_update). Please note that
32
+ # callbacks are executed in the order they were defined in
33
+ # model. You should avoid modyfing the association content, before
34
+ # autosave callbacks are executed. Placing your callbacks after
35
+ # associations is usually a good practice.
36
+ #
37
+ # == Examples
38
+ #
39
+ # === One-to-one Example
21
40
  #
22
41
  # class Post
23
42
  # has_one :author, :autosave => true
@@ -27,7 +46,7 @@ module ActiveRecord
27
46
  # automatically _and_ atomically:
28
47
  #
29
48
  # post = Post.find(1)
30
- # post.title # => "The current global position of migrating ducks"
49
+ # post.title # => "The current global position of migrating ducks"
31
50
  # post.author.name # => "alloy"
32
51
  #
33
52
  # post.title = "On the migration of ducks"
@@ -35,7 +54,7 @@ module ActiveRecord
35
54
  #
36
55
  # post.save
37
56
  # post.reload
38
- # post.title # => "On the migration of ducks"
57
+ # post.title # => "On the migration of ducks"
39
58
  # post.author.name # => "Eloy Duran"
40
59
  #
41
60
  # Destroying an associated model, as part of the parent's save action, is as
@@ -45,6 +64,7 @@ module ActiveRecord
45
64
  # post.author.marked_for_destruction? # => true
46
65
  #
47
66
  # Note that the model is _not_ yet removed from the database:
67
+ #
48
68
  # id = post.author.id
49
69
  # Author.find_by_id(id).nil? # => false
50
70
  #
@@ -52,40 +72,49 @@ module ActiveRecord
52
72
  # post.reload.author # => nil
53
73
  #
54
74
  # Now it _is_ removed from the database:
75
+ #
55
76
  # Author.find_by_id(id).nil? # => true
56
77
  #
57
78
  # === One-to-many Example
58
79
  #
59
- # Consider a Post model with many Comments:
80
+ # When <tt>:autosave</tt> is not declared new children are saved when their parent is saved:
60
81
  #
61
82
  # class Post
62
- # has_many :comments, :autosave => true
83
+ # has_many :comments # :autosave option is no declared
63
84
  # end
64
85
  #
65
- # Saving changes to the parent and its associated model can now be performed
66
- # automatically _and_ atomically:
86
+ # post = Post.new(:title => 'ruby rocks')
87
+ # post.comments.build(:body => 'hello world')
88
+ # post.save # => saves both post and comment
67
89
  #
68
- # post = Post.find(1)
69
- # post.title # => "The current global position of migrating ducks"
70
- # post.comments.first.body # => "Wow, awesome info thanks!"
71
- # post.comments.last.body # => "Actually, your article should be named differently."
90
+ # post = Post.create(:title => 'ruby rocks')
91
+ # post.comments.build(:body => 'hello world')
92
+ # post.save # => saves both post and comment
72
93
  #
73
- # post.title = "On the migration of ducks"
74
- # post.comments.last.body = "Actually, your article should be named differently. [UPDATED]: You are right, thanks."
94
+ # post = Post.create(:title => 'ruby rocks')
95
+ # post.comments.create(:body => 'hello world')
96
+ # post.save # => saves both post and comment
75
97
  #
76
- # post.save
77
- # post.reload
78
- # post.title # => "On the migration of ducks"
79
- # post.comments.last.body # => "Actually, your article should be named differently. [UPDATED]: You are right, thanks."
98
+ # When <tt>:autosave</tt> is true all children is saved, no matter whether they are new records:
80
99
  #
81
- # Destroying one of the associated models members, as part of the parent's
82
- # save action, is as simple as marking it for destruction:
100
+ # class Post
101
+ # has_many :comments, :autosave => true
102
+ # end
103
+ #
104
+ # post = Post.create(:title => 'ruby rocks')
105
+ # post.comments.create(:body => 'hello world')
106
+ # post.comments[0].body = 'hi everyone'
107
+ # post.save # => saves both post and comment, with 'hi everyone' as body
108
+ #
109
+ # Destroying one of the associated models as part of the parent's save action
110
+ # is as simple as marking it for destruction:
83
111
  #
84
112
  # post.comments.last.mark_for_destruction
85
113
  # post.comments.last.marked_for_destruction? # => true
86
114
  # post.comments.length # => 2
87
115
  #
88
116
  # Note that the model is _not_ yet removed from the database:
117
+ #
89
118
  # id = post.comments.last.id
90
119
  # Comment.find_by_id(id).nil? # => false
91
120
  #
@@ -93,72 +122,58 @@ module ActiveRecord
93
122
  # post.reload.comments.length # => 1
94
123
  #
95
124
  # Now it _is_ removed from the database:
96
- # Comment.find_by_id(id).nil? # => true
97
- #
98
- # === Validation
99
- #
100
- # Validation is performed on the parent as usual, but also on all autosave
101
- # enabled associations. If any of the associations fail validation, its
102
- # error messages will be applied on the parents errors object and validation
103
- # of the parent will fail.
104
- #
105
- # Consider a Post model with Author which validates the presence of its name
106
- # attribute:
107
- #
108
- # class Post
109
- # has_one :author, :autosave => true
110
- # end
111
- #
112
- # class Author
113
- # validates_presence_of :name
114
- # end
115
- #
116
- # post = Post.find(1)
117
- # post.author.name = ''
118
- # post.save # => false
119
- # post.errors # => #<ActiveRecord::Errors:0x174498c @errors={"author_name"=>["can't be blank"]}, @base=#<Post ...>>
120
- #
121
- # No validations will be performed on the associated models when validations
122
- # are skipped for the parent:
123
125
  #
124
- # post = Post.find(1)
125
- # post.author.name = ''
126
- # post.save(false) # => true
126
+ # Comment.find_by_id(id).nil? # => true
127
+
127
128
  module AutosaveAssociation
128
- ASSOCIATION_TYPES = %w{ has_one belongs_to has_many has_and_belongs_to_many }
129
+ extend ActiveSupport::Concern
129
130
 
130
- def self.included(base)
131
- base.class_eval do
132
- base.extend(ClassMethods)
133
- alias_method_chain :reload, :autosave_associations
131
+ ASSOCIATION_TYPES = %w{ HasOne HasMany BelongsTo HasAndBelongsToMany }
134
132
 
135
- ASSOCIATION_TYPES.each do |type|
136
- base.send("valid_keys_for_#{type}_association") << :autosave
137
- end
133
+ module AssociationBuilderExtension #:nodoc:
134
+ def self.included(base)
135
+ base.valid_options << :autosave
136
+ end
137
+
138
+ def build
139
+ reflection = super
140
+ model.send(:add_autosave_association_callbacks, reflection)
141
+ reflection
142
+ end
143
+ end
144
+
145
+ included do
146
+ ASSOCIATION_TYPES.each do |type|
147
+ Associations::Builder.const_get(type).send(:include, AssociationBuilderExtension)
138
148
  end
139
149
  end
140
150
 
141
151
  module ClassMethods
142
152
  private
143
153
 
144
- # def belongs_to(name, options = {})
145
- # super
146
- # add_autosave_association_callbacks(reflect_on_association(name))
147
- # end
148
- ASSOCIATION_TYPES.each do |type|
149
- module_eval <<-CODE, __FILE__, __LINE__ + 1
150
- def #{type}(name, options = {})
151
- super
152
- add_autosave_association_callbacks(reflect_on_association(name))
154
+ def define_non_cyclic_method(name, reflection, &block)
155
+ define_method(name) do |*args|
156
+ result = true; @_already_called ||= {}
157
+ # Loop prevention for validation of associations
158
+ unless @_already_called[[name, reflection.name]]
159
+ begin
160
+ @_already_called[[name, reflection.name]]=true
161
+ result = instance_eval(&block)
162
+ ensure
163
+ @_already_called[[name, reflection.name]]=false
164
+ end
153
165
  end
154
- CODE
166
+
167
+ result
168
+ end
155
169
  end
156
170
 
157
- # Adds a validate and save callback for the association as specified by
171
+ # Adds validation and save callbacks for the association as specified by
158
172
  # the +reflection+.
159
173
  #
160
- # For performance reasons, we don't check whether to validate at runtime,
161
- # but instead only define the method and callback when needed. However,
174
+ # For performance reasons, we don't check whether to validate at runtime.
175
+ # However the validation and callback methods are lazy and those methods
176
+ # get created when they are invoked for the very first time. However,
162
177
  # this can change, for instance, when using nested attributes, which is
163
178
  # called _after_ the association has been defined. Since we don't want
164
179
  # the callbacks to get defined multiple times, there are guards that
@@ -173,16 +188,25 @@ module ActiveRecord
173
188
  if collection
174
189
  before_save :before_save_collection_association
175
190
 
176
- define_method(save_method) { save_collection_association(reflection) }
191
+ define_non_cyclic_method(save_method, reflection) { save_collection_association(reflection) }
177
192
  # Doesn't use after_save as that would save associations added in after_create/after_update twice
178
193
  after_create save_method
179
194
  after_update save_method
180
195
  else
181
196
  if reflection.macro == :has_one
182
197
  define_method(save_method) { save_has_one_association(reflection) }
183
- after_save save_method
198
+ # Configures two callbacks instead of a single after_save so that
199
+ # the model may rely on their execution order relative to its
200
+ # own callbacks.
201
+ #
202
+ # For example, given that after_creates run before after_saves, if
203
+ # we configured instead an after_save there would be no way to fire
204
+ # a custom after_create callback after the child association gets
205
+ # created.
206
+ after_create save_method
207
+ after_update save_method
184
208
  else
185
- define_method(save_method) { save_belongs_to_association(reflection) }
209
+ define_non_cyclic_method(save_method, reflection) { save_belongs_to_association(reflection) }
186
210
  before_save save_method
187
211
  end
188
212
  end
@@ -190,20 +214,21 @@ module ActiveRecord
190
214
 
191
215
  if reflection.validate? && !method_defined?(validation_method)
192
216
  method = (collection ? :validate_collection_association : :validate_single_association)
193
- define_method(validation_method) { send(method, reflection) }
217
+ define_non_cyclic_method(validation_method, reflection) { send(method, reflection) }
194
218
  validate validation_method
195
219
  end
196
220
  end
197
221
  end
198
222
 
199
- # Reloads the attributes of the object as usual and removes a mark for destruction.
200
- def reload_with_autosave_associations(options = nil)
223
+ # Reloads the attributes of the object as usual and clears <tt>marked_for_destruction</tt> flag.
224
+ def reload(options = nil)
201
225
  @marked_for_destruction = false
202
- reload_without_autosave_associations(options)
226
+ super
203
227
  end
204
228
 
205
229
  # Marks this record to be destroyed as part of the parents save transaction.
206
- # This does _not_ actually destroy the record yet, rather it will be destroyed when <tt>parent.save</tt> is called.
230
+ # This does _not_ actually destroy the record instantly, rather child record will be destroyed
231
+ # when <tt>parent.save</tt> is called.
207
232
  #
208
233
  # Only useful if the <tt>:autosave</tt> option on the parent is enabled for this associated model.
209
234
  def mark_for_destruction
@@ -222,7 +247,7 @@ module ActiveRecord
222
247
  def changed_for_autosave?
223
248
  new_record? || changed? || marked_for_destruction? || nested_records_changed_for_autosave?
224
249
  end
225
-
250
+
226
251
  private
227
252
 
228
253
  # Returns the record for an association collection that should be validated
@@ -230,35 +255,29 @@ module ActiveRecord
230
255
  # unless the parent is/was a new record itself.
231
256
  def associated_records_to_validate_or_save(association, new_record, autosave)
232
257
  if new_record
233
- association
258
+ association && association.target
234
259
  elsif autosave
235
- association.target.select { |record| record.changed_for_autosave? }
260
+ association.target.find_all { |record| record.changed_for_autosave? }
236
261
  else
237
- association.target.select { |record| record.new_record? }
262
+ association.target.find_all { |record| record.new_record? }
238
263
  end
239
264
  end
240
-
265
+
241
266
  # go through nested autosave associations that are loaded in memory (without loading
242
267
  # any new ones), and return true if is changed for autosave
243
268
  def nested_records_changed_for_autosave?
244
- self.class.reflect_on_all_autosave_associations.each do |reflection|
245
- if association = association_instance_get(reflection.name)
246
- if [:belongs_to, :has_one].include?(reflection.macro)
247
- return true if association.target && association.target.changed_for_autosave?
248
- else
249
- association.target.each {|record| return true if record.changed_for_autosave? }
250
- end
251
- end
269
+ self.class.reflect_on_all_autosave_associations.any? do |reflection|
270
+ association = association_instance_get(reflection.name)
271
+ association && Array.wrap(association.target).any? { |a| a.changed_for_autosave? }
252
272
  end
253
- false
254
273
  end
255
-
274
+
256
275
  # Validate the association if <tt>:validate</tt> or <tt>:autosave</tt> is
257
- # turned on for the association specified by +reflection+.
276
+ # turned on for the association.
258
277
  def validate_single_association(reflection)
259
- if (association = association_instance_get(reflection.name)) && !association.target.nil?
260
- association_valid?(reflection, association)
261
- end
278
+ association = association_instance_get(reflection.name)
279
+ record = association && association.reader
280
+ association_valid?(reflection, record) if record
262
281
  end
263
282
 
264
283
  # Validate the associated records if <tt>:validate</tt> or
@@ -275,14 +294,15 @@ module ActiveRecord
275
294
  # Returns whether or not the association is valid and applies any errors to
276
295
  # the parent, <tt>self</tt>, if it wasn't. Skips any <tt>:autosave</tt>
277
296
  # enabled records if they're marked_for_destruction? or destroyed.
278
- def association_valid?(reflection, association)
279
- return true if association.destroyed? || association.marked_for_destruction?
297
+ def association_valid?(reflection, record)
298
+ return true if record.destroyed? || record.marked_for_destruction?
280
299
 
281
- unless valid = association.valid?
300
+ unless valid = record.valid?
282
301
  if reflection.options[:autosave]
283
- association.errors.each_error do |attribute, error|
302
+ record.errors.each do |attribute, message|
284
303
  attribute = "#{reflection.name}.#{attribute}"
285
- errors.add(attribute, error.dup) unless errors.on(attribute)
304
+ errors[attribute] << message
305
+ errors[attribute].uniq!
286
306
  end
287
307
  else
288
308
  errors.add(reflection.name)
@@ -311,27 +331,38 @@ module ActiveRecord
311
331
  autosave = reflection.options[:autosave]
312
332
 
313
333
  if records = associated_records_to_validate_or_save(association, @new_record_before_save, autosave)
314
- records.each do |record|
315
- next if record.destroyed?
316
-
317
- if autosave && record.marked_for_destruction?
318
- association.destroy(record)
319
- elsif autosave != false && (@new_record_before_save || record.new_record?)
320
- if autosave
321
- saved = association.send(:insert_record, record, false, false)
322
- else
323
- association.send(:insert_record, record)
324
- end
325
- elsif autosave
326
- saved = record.save(false)
334
+ begin
335
+ if autosave
336
+ records_to_destroy = records.select(&:marked_for_destruction?)
337
+ records_to_destroy.each { |record| association.proxy.destroy(record) }
338
+ records -= records_to_destroy
327
339
  end
328
340
 
329
- raise ActiveRecord::Rollback if saved == false
341
+ records.each do |record|
342
+ next if record.destroyed?
343
+
344
+ saved = true
345
+
346
+ if autosave != false && (@new_record_before_save || record.new_record?)
347
+ if autosave
348
+ saved = association.insert_record(record, false)
349
+ else
350
+ association.insert_record(record) unless reflection.nested?
351
+ end
352
+ elsif autosave
353
+ saved = record.save(:validate => false)
354
+ end
355
+
356
+ raise ActiveRecord::Rollback unless saved
357
+ end
358
+ rescue
359
+ records.each {|x| IdentityMap.remove(x) } if IdentityMap.enabled?
360
+ raise
330
361
  end
331
362
  end
332
363
 
333
- # reconstruct the SQL queries now that we know the owner's id
334
- association.send(:construct_sql) if association.respond_to?(:construct_sql)
364
+ # reconstruct the scope now that we know the owner's id
365
+ association.reset_scope if association.respond_to?(:reset_scope)
335
366
  end
336
367
  end
337
368
 
@@ -344,16 +375,21 @@ module ActiveRecord
344
375
  # This all happens inside a transaction, _if_ the Transactions module is included into
345
376
  # ActiveRecord::Base after the AutosaveAssociation module, which it does by default.
346
377
  def save_has_one_association(reflection)
347
- if (association = association_instance_get(reflection.name)) && !association.target.nil? && !association.destroyed?
378
+ association = association_instance_get(reflection.name)
379
+ record = association && association.load_target
380
+ if record && !record.destroyed?
348
381
  autosave = reflection.options[:autosave]
349
382
 
350
- if autosave && association.marked_for_destruction?
351
- association.destroy
383
+ if autosave && record.marked_for_destruction?
384
+ record.destroy
352
385
  else
353
386
  key = reflection.options[:primary_key] ? send(reflection.options[:primary_key]) : id
354
- if autosave != false && (new_record? || association.new_record? || association[reflection.primary_key_name] != key || autosave)
355
- association[reflection.primary_key_name] = key
356
- saved = association.save(!autosave)
387
+ if autosave != false && (new_record? || record.new_record? || record[reflection.foreign_key] != key || autosave)
388
+ unless reflection.through_reflection
389
+ record[reflection.foreign_key] = key
390
+ end
391
+
392
+ saved = record.save(:validate => !autosave)
357
393
  raise ActiveRecord::Rollback if !saved && autosave
358
394
  saved
359
395
  end
@@ -361,30 +397,24 @@ module ActiveRecord
361
397
  end
362
398
  end
363
399
 
364
- # Saves the associated record if it's new or <tt>:autosave</tt> is enabled
365
- # on the association.
400
+ # Saves the associated record if it's new or <tt>:autosave</tt> is enabled.
366
401
  #
367
- # In addition, it will destroy the association if it was marked for
368
- # destruction with mark_for_destruction.
369
- #
370
- # This all happens inside a transaction, _if_ the Transactions module is included into
371
- # ActiveRecord::Base after the AutosaveAssociation module, which it does by default.
402
+ # In addition, it will destroy the association if it was marked for destruction.
372
403
  def save_belongs_to_association(reflection)
373
- if (association = association_instance_get(reflection.name)) && !association.destroyed?
404
+ association = association_instance_get(reflection.name)
405
+ record = association && association.load_target
406
+ if record && !record.destroyed?
374
407
  autosave = reflection.options[:autosave]
375
408
 
376
- if autosave && association.marked_for_destruction?
377
- association.destroy
409
+ if autosave && record.marked_for_destruction?
410
+ record.destroy
378
411
  elsif autosave != false
379
- saved = association.save(!autosave) if association.new_record? || autosave
412
+ saved = record.save(:validate => !autosave) if record.new_record? || (autosave && record.changed_for_autosave?)
380
413
 
381
414
  if association.updated?
382
- association_id = association.send(reflection.options[:primary_key] || :id)
383
- self[reflection.primary_key_name] = association_id
384
- # TODO: Removing this code doesn't seem to matter…
385
- if reflection.options[:polymorphic]
386
- self[reflection.options[:foreign_type]] = association.class.base_class.name.to_s
387
- end
415
+ association_id = record.send(reflection.options[:primary_key] || :id)
416
+ self[reflection.foreign_key] = association_id
417
+ association.loaded!
388
418
  end
389
419
 
390
420
  saved if autosave