activerecord_csi 2.3.5.p6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (333) hide show
  1. data/CHANGELOG +5858 -0
  2. data/README +351 -0
  3. data/RUNNING_UNIT_TESTS +36 -0
  4. data/Rakefile +270 -0
  5. data/examples/associations.png +0 -0
  6. data/examples/performance.rb +162 -0
  7. data/install.rb +30 -0
  8. data/lib/active_record/aggregations.rb +261 -0
  9. data/lib/active_record/association_preload.rb +389 -0
  10. data/lib/active_record/associations/association_collection.rb +475 -0
  11. data/lib/active_record/associations/association_proxy.rb +278 -0
  12. data/lib/active_record/associations/belongs_to_association.rb +76 -0
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +53 -0
  14. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +143 -0
  15. data/lib/active_record/associations/has_many_association.rb +122 -0
  16. data/lib/active_record/associations/has_many_through_association.rb +266 -0
  17. data/lib/active_record/associations/has_one_association.rb +133 -0
  18. data/lib/active_record/associations/has_one_through_association.rb +37 -0
  19. data/lib/active_record/associations.rb +2241 -0
  20. data/lib/active_record/attribute_methods.rb +388 -0
  21. data/lib/active_record/autosave_association.rb +364 -0
  22. data/lib/active_record/base.rb +3171 -0
  23. data/lib/active_record/batches.rb +81 -0
  24. data/lib/active_record/calculations.rb +311 -0
  25. data/lib/active_record/callbacks.rb +360 -0
  26. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +371 -0
  27. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +139 -0
  28. data/lib/active_record/connection_adapters/abstract/database_statements.rb +289 -0
  29. data/lib/active_record/connection_adapters/abstract/query_cache.rb +94 -0
  30. data/lib/active_record/connection_adapters/abstract/quoting.rb +69 -0
  31. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +722 -0
  32. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +434 -0
  33. data/lib/active_record/connection_adapters/abstract_adapter.rb +241 -0
  34. data/lib/active_record/connection_adapters/mysql_adapter.rb +630 -0
  35. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1113 -0
  36. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -0
  37. data/lib/active_record/connection_adapters/sqlite_adapter.rb +453 -0
  38. data/lib/active_record/dirty.rb +183 -0
  39. data/lib/active_record/dynamic_finder_match.rb +41 -0
  40. data/lib/active_record/dynamic_scope_match.rb +25 -0
  41. data/lib/active_record/fixtures.rb +996 -0
  42. data/lib/active_record/i18n_interpolation_deprecation.rb +26 -0
  43. data/lib/active_record/locale/en.yml +58 -0
  44. data/lib/active_record/locking/optimistic.rb +148 -0
  45. data/lib/active_record/locking/pessimistic.rb +55 -0
  46. data/lib/active_record/migration.rb +566 -0
  47. data/lib/active_record/named_scope.rb +192 -0
  48. data/lib/active_record/nested_attributes.rb +392 -0
  49. data/lib/active_record/observer.rb +197 -0
  50. data/lib/active_record/query_cache.rb +33 -0
  51. data/lib/active_record/reflection.rb +320 -0
  52. data/lib/active_record/schema.rb +51 -0
  53. data/lib/active_record/schema_dumper.rb +182 -0
  54. data/lib/active_record/serialization.rb +101 -0
  55. data/lib/active_record/serializers/json_serializer.rb +91 -0
  56. data/lib/active_record/serializers/xml_serializer.rb +357 -0
  57. data/lib/active_record/session_store.rb +326 -0
  58. data/lib/active_record/test_case.rb +66 -0
  59. data/lib/active_record/timestamp.rb +71 -0
  60. data/lib/active_record/transactions.rb +235 -0
  61. data/lib/active_record/validations.rb +1135 -0
  62. data/lib/active_record/version.rb +9 -0
  63. data/lib/active_record.rb +84 -0
  64. data/lib/activerecord.rb +2 -0
  65. data/test/assets/example.log +1 -0
  66. data/test/assets/flowers.jpg +0 -0
  67. data/test/cases/aaa_create_tables_test.rb +24 -0
  68. data/test/cases/active_schema_test_mysql.rb +100 -0
  69. data/test/cases/active_schema_test_postgresql.rb +24 -0
  70. data/test/cases/adapter_test.rb +145 -0
  71. data/test/cases/aggregations_test.rb +167 -0
  72. data/test/cases/ar_schema_test.rb +32 -0
  73. data/test/cases/associations/belongs_to_associations_test.rb +425 -0
  74. data/test/cases/associations/callbacks_test.rb +161 -0
  75. data/test/cases/associations/cascaded_eager_loading_test.rb +131 -0
  76. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +36 -0
  77. data/test/cases/associations/eager_load_nested_include_test.rb +130 -0
  78. data/test/cases/associations/eager_singularization_test.rb +145 -0
  79. data/test/cases/associations/eager_test.rb +834 -0
  80. data/test/cases/associations/extension_test.rb +62 -0
  81. data/test/cases/associations/habtm_join_table_test.rb +56 -0
  82. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +822 -0
  83. data/test/cases/associations/has_many_associations_test.rb +1134 -0
  84. data/test/cases/associations/has_many_through_associations_test.rb +346 -0
  85. data/test/cases/associations/has_one_associations_test.rb +330 -0
  86. data/test/cases/associations/has_one_through_associations_test.rb +209 -0
  87. data/test/cases/associations/inner_join_association_test.rb +93 -0
  88. data/test/cases/associations/join_model_test.rb +712 -0
  89. data/test/cases/associations_test.rb +262 -0
  90. data/test/cases/attribute_methods_test.rb +305 -0
  91. data/test/cases/autosave_association_test.rb +1142 -0
  92. data/test/cases/base_test.rb +2154 -0
  93. data/test/cases/batches_test.rb +61 -0
  94. data/test/cases/binary_test.rb +30 -0
  95. data/test/cases/calculations_test.rb +348 -0
  96. data/test/cases/callbacks_observers_test.rb +38 -0
  97. data/test/cases/callbacks_test.rb +438 -0
  98. data/test/cases/class_inheritable_attributes_test.rb +32 -0
  99. data/test/cases/column_alias_test.rb +17 -0
  100. data/test/cases/column_definition_test.rb +70 -0
  101. data/test/cases/connection_pool_test.rb +25 -0
  102. data/test/cases/connection_test_firebird.rb +8 -0
  103. data/test/cases/connection_test_mysql.rb +64 -0
  104. data/test/cases/copy_table_test_sqlite.rb +80 -0
  105. data/test/cases/database_statements_test.rb +12 -0
  106. data/test/cases/datatype_test_postgresql.rb +204 -0
  107. data/test/cases/date_time_test.rb +37 -0
  108. data/test/cases/default_test_firebird.rb +16 -0
  109. data/test/cases/defaults_test.rb +111 -0
  110. data/test/cases/deprecated_finder_test.rb +30 -0
  111. data/test/cases/dirty_test.rb +316 -0
  112. data/test/cases/finder_respond_to_test.rb +76 -0
  113. data/test/cases/finder_test.rb +1066 -0
  114. data/test/cases/fixtures_test.rb +656 -0
  115. data/test/cases/helper.rb +68 -0
  116. data/test/cases/i18n_test.rb +46 -0
  117. data/test/cases/inheritance_test.rb +262 -0
  118. data/test/cases/invalid_date_test.rb +24 -0
  119. data/test/cases/json_serialization_test.rb +205 -0
  120. data/test/cases/lifecycle_test.rb +193 -0
  121. data/test/cases/locking_test.rb +304 -0
  122. data/test/cases/method_scoping_test.rb +704 -0
  123. data/test/cases/migration_test.rb +1523 -0
  124. data/test/cases/migration_test_firebird.rb +124 -0
  125. data/test/cases/mixin_test.rb +96 -0
  126. data/test/cases/modules_test.rb +81 -0
  127. data/test/cases/multiple_db_test.rb +85 -0
  128. data/test/cases/named_scope_test.rb +361 -0
  129. data/test/cases/nested_attributes_test.rb +581 -0
  130. data/test/cases/pk_test.rb +119 -0
  131. data/test/cases/pooled_connections_test.rb +103 -0
  132. data/test/cases/query_cache_test.rb +123 -0
  133. data/test/cases/readonly_test.rb +107 -0
  134. data/test/cases/reflection_test.rb +194 -0
  135. data/test/cases/reload_models_test.rb +22 -0
  136. data/test/cases/repair_helper.rb +50 -0
  137. data/test/cases/reserved_word_test_mysql.rb +176 -0
  138. data/test/cases/sanitize_test.rb +25 -0
  139. data/test/cases/schema_authorization_test_postgresql.rb +75 -0
  140. data/test/cases/schema_dumper_test.rb +211 -0
  141. data/test/cases/schema_test_postgresql.rb +178 -0
  142. data/test/cases/serialization_test.rb +47 -0
  143. data/test/cases/synonym_test_oracle.rb +17 -0
  144. data/test/cases/timestamp_test.rb +75 -0
  145. data/test/cases/transactions_test.rb +522 -0
  146. data/test/cases/unconnected_test.rb +32 -0
  147. data/test/cases/validations_i18n_test.rb +955 -0
  148. data/test/cases/validations_test.rb +1640 -0
  149. data/test/cases/xml_serialization_test.rb +240 -0
  150. data/test/config.rb +5 -0
  151. data/test/connections/jdbc_jdbcderby/connection.rb +18 -0
  152. data/test/connections/jdbc_jdbch2/connection.rb +18 -0
  153. data/test/connections/jdbc_jdbchsqldb/connection.rb +18 -0
  154. data/test/connections/jdbc_jdbcmysql/connection.rb +26 -0
  155. data/test/connections/jdbc_jdbcpostgresql/connection.rb +26 -0
  156. data/test/connections/jdbc_jdbcsqlite3/connection.rb +25 -0
  157. data/test/connections/native_db2/connection.rb +25 -0
  158. data/test/connections/native_firebird/connection.rb +26 -0
  159. data/test/connections/native_frontbase/connection.rb +27 -0
  160. data/test/connections/native_mysql/connection.rb +25 -0
  161. data/test/connections/native_openbase/connection.rb +21 -0
  162. data/test/connections/native_oracle/connection.rb +27 -0
  163. data/test/connections/native_postgresql/connection.rb +25 -0
  164. data/test/connections/native_sqlite/connection.rb +25 -0
  165. data/test/connections/native_sqlite3/connection.rb +25 -0
  166. data/test/connections/native_sqlite3/in_memory_connection.rb +18 -0
  167. data/test/connections/native_sybase/connection.rb +23 -0
  168. data/test/fixtures/accounts.yml +29 -0
  169. data/test/fixtures/all/developers.yml +0 -0
  170. data/test/fixtures/all/people.csv +0 -0
  171. data/test/fixtures/all/tasks.yml +0 -0
  172. data/test/fixtures/author_addresses.yml +5 -0
  173. data/test/fixtures/author_favorites.yml +4 -0
  174. data/test/fixtures/authors.yml +9 -0
  175. data/test/fixtures/binaries.yml +132 -0
  176. data/test/fixtures/books.yml +7 -0
  177. data/test/fixtures/categories/special_categories.yml +9 -0
  178. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
  179. data/test/fixtures/categories.yml +14 -0
  180. data/test/fixtures/categories_ordered.yml +7 -0
  181. data/test/fixtures/categories_posts.yml +23 -0
  182. data/test/fixtures/categorizations.yml +17 -0
  183. data/test/fixtures/clubs.yml +6 -0
  184. data/test/fixtures/comments.yml +59 -0
  185. data/test/fixtures/companies.yml +56 -0
  186. data/test/fixtures/computers.yml +4 -0
  187. data/test/fixtures/courses.yml +7 -0
  188. data/test/fixtures/customers.yml +26 -0
  189. data/test/fixtures/developers.yml +21 -0
  190. data/test/fixtures/developers_projects.yml +17 -0
  191. data/test/fixtures/edges.yml +6 -0
  192. data/test/fixtures/entrants.yml +14 -0
  193. data/test/fixtures/fixture_database.sqlite3 +0 -0
  194. data/test/fixtures/fixture_database_2.sqlite3 +0 -0
  195. data/test/fixtures/fk_test_has_fk.yml +3 -0
  196. data/test/fixtures/fk_test_has_pk.yml +2 -0
  197. data/test/fixtures/funny_jokes.yml +10 -0
  198. data/test/fixtures/items.yml +4 -0
  199. data/test/fixtures/jobs.yml +7 -0
  200. data/test/fixtures/legacy_things.yml +3 -0
  201. data/test/fixtures/mateys.yml +4 -0
  202. data/test/fixtures/member_types.yml +6 -0
  203. data/test/fixtures/members.yml +6 -0
  204. data/test/fixtures/memberships.yml +20 -0
  205. data/test/fixtures/minimalistics.yml +2 -0
  206. data/test/fixtures/mixed_case_monkeys.yml +6 -0
  207. data/test/fixtures/mixins.yml +29 -0
  208. data/test/fixtures/movies.yml +7 -0
  209. data/test/fixtures/naked/csv/accounts.csv +1 -0
  210. data/test/fixtures/naked/yml/accounts.yml +1 -0
  211. data/test/fixtures/naked/yml/companies.yml +1 -0
  212. data/test/fixtures/naked/yml/courses.yml +1 -0
  213. data/test/fixtures/organizations.yml +5 -0
  214. data/test/fixtures/owners.yml +7 -0
  215. data/test/fixtures/parrots.yml +27 -0
  216. data/test/fixtures/parrots_pirates.yml +7 -0
  217. data/test/fixtures/people.yml +15 -0
  218. data/test/fixtures/pets.yml +14 -0
  219. data/test/fixtures/pirates.yml +9 -0
  220. data/test/fixtures/posts.yml +52 -0
  221. data/test/fixtures/price_estimates.yml +7 -0
  222. data/test/fixtures/projects.yml +7 -0
  223. data/test/fixtures/readers.yml +9 -0
  224. data/test/fixtures/references.yml +17 -0
  225. data/test/fixtures/reserved_words/distinct.yml +5 -0
  226. data/test/fixtures/reserved_words/distincts_selects.yml +11 -0
  227. data/test/fixtures/reserved_words/group.yml +14 -0
  228. data/test/fixtures/reserved_words/select.yml +8 -0
  229. data/test/fixtures/reserved_words/values.yml +7 -0
  230. data/test/fixtures/ships.yml +5 -0
  231. data/test/fixtures/sponsors.yml +9 -0
  232. data/test/fixtures/subscribers.yml +7 -0
  233. data/test/fixtures/subscriptions.yml +12 -0
  234. data/test/fixtures/taggings.yml +28 -0
  235. data/test/fixtures/tags.yml +7 -0
  236. data/test/fixtures/tasks.yml +7 -0
  237. data/test/fixtures/topics.yml +42 -0
  238. data/test/fixtures/toys.yml +4 -0
  239. data/test/fixtures/treasures.yml +10 -0
  240. data/test/fixtures/vertices.yml +4 -0
  241. data/test/fixtures/warehouse-things.yml +3 -0
  242. data/test/migrations/broken/100_migration_that_raises_exception.rb +10 -0
  243. data/test/migrations/decimal/1_give_me_big_numbers.rb +15 -0
  244. data/test/migrations/duplicate/1_people_have_last_names.rb +9 -0
  245. data/test/migrations/duplicate/2_we_need_reminders.rb +12 -0
  246. data/test/migrations/duplicate/3_foo.rb +7 -0
  247. data/test/migrations/duplicate/3_innocent_jointable.rb +12 -0
  248. data/test/migrations/duplicate_names/20080507052938_chunky.rb +7 -0
  249. data/test/migrations/duplicate_names/20080507053028_chunky.rb +7 -0
  250. data/test/migrations/interleaved/pass_1/3_innocent_jointable.rb +12 -0
  251. data/test/migrations/interleaved/pass_2/1_people_have_last_names.rb +9 -0
  252. data/test/migrations/interleaved/pass_2/3_innocent_jointable.rb +12 -0
  253. data/test/migrations/interleaved/pass_3/1_people_have_last_names.rb +9 -0
  254. data/test/migrations/interleaved/pass_3/2_i_raise_on_down.rb +8 -0
  255. data/test/migrations/interleaved/pass_3/3_innocent_jointable.rb +12 -0
  256. data/test/migrations/missing/1000_people_have_middle_names.rb +9 -0
  257. data/test/migrations/missing/1_people_have_last_names.rb +9 -0
  258. data/test/migrations/missing/3_we_need_reminders.rb +12 -0
  259. data/test/migrations/missing/4_innocent_jointable.rb +12 -0
  260. data/test/migrations/valid/1_people_have_last_names.rb +9 -0
  261. data/test/migrations/valid/2_we_need_reminders.rb +12 -0
  262. data/test/migrations/valid/3_innocent_jointable.rb +12 -0
  263. data/test/models/author.rb +146 -0
  264. data/test/models/auto_id.rb +4 -0
  265. data/test/models/binary.rb +2 -0
  266. data/test/models/bird.rb +3 -0
  267. data/test/models/book.rb +4 -0
  268. data/test/models/categorization.rb +5 -0
  269. data/test/models/category.rb +34 -0
  270. data/test/models/citation.rb +6 -0
  271. data/test/models/club.rb +13 -0
  272. data/test/models/column_name.rb +3 -0
  273. data/test/models/comment.rb +29 -0
  274. data/test/models/company.rb +171 -0
  275. data/test/models/company_in_module.rb +61 -0
  276. data/test/models/computer.rb +3 -0
  277. data/test/models/contact.rb +16 -0
  278. data/test/models/contract.rb +5 -0
  279. data/test/models/course.rb +3 -0
  280. data/test/models/customer.rb +73 -0
  281. data/test/models/default.rb +2 -0
  282. data/test/models/developer.rb +101 -0
  283. data/test/models/edge.rb +5 -0
  284. data/test/models/entrant.rb +3 -0
  285. data/test/models/essay.rb +3 -0
  286. data/test/models/event.rb +3 -0
  287. data/test/models/guid.rb +2 -0
  288. data/test/models/item.rb +7 -0
  289. data/test/models/job.rb +5 -0
  290. data/test/models/joke.rb +3 -0
  291. data/test/models/keyboard.rb +3 -0
  292. data/test/models/legacy_thing.rb +3 -0
  293. data/test/models/matey.rb +4 -0
  294. data/test/models/member.rb +12 -0
  295. data/test/models/member_detail.rb +5 -0
  296. data/test/models/member_type.rb +3 -0
  297. data/test/models/membership.rb +9 -0
  298. data/test/models/minimalistic.rb +2 -0
  299. data/test/models/mixed_case_monkey.rb +3 -0
  300. data/test/models/movie.rb +5 -0
  301. data/test/models/order.rb +4 -0
  302. data/test/models/organization.rb +6 -0
  303. data/test/models/owner.rb +5 -0
  304. data/test/models/parrot.rb +16 -0
  305. data/test/models/person.rb +16 -0
  306. data/test/models/pet.rb +5 -0
  307. data/test/models/pirate.rb +70 -0
  308. data/test/models/post.rb +100 -0
  309. data/test/models/price_estimate.rb +3 -0
  310. data/test/models/project.rb +30 -0
  311. data/test/models/reader.rb +4 -0
  312. data/test/models/reference.rb +4 -0
  313. data/test/models/reply.rb +46 -0
  314. data/test/models/ship.rb +10 -0
  315. data/test/models/ship_part.rb +5 -0
  316. data/test/models/sponsor.rb +4 -0
  317. data/test/models/subject.rb +4 -0
  318. data/test/models/subscriber.rb +8 -0
  319. data/test/models/subscription.rb +4 -0
  320. data/test/models/tag.rb +7 -0
  321. data/test/models/tagging.rb +10 -0
  322. data/test/models/task.rb +3 -0
  323. data/test/models/topic.rb +80 -0
  324. data/test/models/toy.rb +6 -0
  325. data/test/models/treasure.rb +8 -0
  326. data/test/models/vertex.rb +9 -0
  327. data/test/models/warehouse_thing.rb +5 -0
  328. data/test/schema/mysql_specific_schema.rb +24 -0
  329. data/test/schema/postgresql_specific_schema.rb +114 -0
  330. data/test/schema/schema.rb +493 -0
  331. data/test/schema/schema2.rb +6 -0
  332. data/test/schema/sqlite_specific_schema.rb +25 -0
  333. metadata +420 -0
@@ -0,0 +1,316 @@
1
+ require 'cases/helper'
2
+ require 'models/topic' # For booleans
3
+ require 'models/pirate' # For timestamps
4
+ require 'models/parrot'
5
+ require 'models/person' # For optimistic locking
6
+
7
+ class Pirate # Just reopening it, not defining it
8
+ attr_accessor :detected_changes_in_after_update # Boolean for if changes are detected
9
+ attr_accessor :changes_detected_in_after_update # Actual changes
10
+
11
+ after_update :check_changes
12
+
13
+ private
14
+ # after_save/update in sweepers, observers, and the model itself
15
+ # can end up checking dirty status and acting on the results
16
+ def check_changes
17
+ if self.changed?
18
+ self.detected_changes_in_after_update = true
19
+ self.changes_detected_in_after_update = self.changes
20
+ end
21
+ end
22
+ end
23
+
24
+ class NumericData < ActiveRecord::Base
25
+ self.table_name = 'numeric_data'
26
+ end
27
+
28
+ class DirtyTest < ActiveRecord::TestCase
29
+ def test_attribute_changes
30
+ # New record - no changes.
31
+ pirate = Pirate.new
32
+ assert !pirate.catchphrase_changed?
33
+ assert_nil pirate.catchphrase_change
34
+
35
+ # Change catchphrase.
36
+ pirate.catchphrase = 'arrr'
37
+ assert pirate.catchphrase_changed?
38
+ assert_nil pirate.catchphrase_was
39
+ assert_equal [nil, 'arrr'], pirate.catchphrase_change
40
+
41
+ # Saved - no changes.
42
+ pirate.save!
43
+ assert !pirate.catchphrase_changed?
44
+ assert_nil pirate.catchphrase_change
45
+
46
+ # Same value - no changes.
47
+ pirate.catchphrase = 'arrr'
48
+ assert !pirate.catchphrase_changed?
49
+ assert_nil pirate.catchphrase_change
50
+ end
51
+
52
+ def test_aliased_attribute_changes
53
+ # the actual attribute here is name, title is an
54
+ # alias setup via alias_attribute
55
+ parrot = Parrot.new
56
+ assert !parrot.title_changed?
57
+ assert_nil parrot.title_change
58
+
59
+ parrot.name = 'Sam'
60
+ assert parrot.title_changed?
61
+ assert_nil parrot.title_was
62
+ assert_equal parrot.name_change, parrot.title_change
63
+ end
64
+
65
+ def test_nullable_number_not_marked_as_changed_if_new_value_is_blank
66
+ pirate = Pirate.new
67
+
68
+ ["", nil].each do |value|
69
+ pirate.parrot_id = value
70
+ assert !pirate.parrot_id_changed?
71
+ assert_nil pirate.parrot_id_change
72
+ end
73
+ end
74
+
75
+ def test_nullable_decimal_not_marked_as_changed_if_new_value_is_blank
76
+ numeric_data = NumericData.new
77
+
78
+ ["", nil].each do |value|
79
+ numeric_data.bank_balance = value
80
+ assert !numeric_data.bank_balance_changed?
81
+ assert_nil numeric_data.bank_balance_change
82
+ end
83
+ end
84
+
85
+ def test_nullable_float_not_marked_as_changed_if_new_value_is_blank
86
+ numeric_data = NumericData.new
87
+
88
+ ["", nil].each do |value|
89
+ numeric_data.temperature = value
90
+ assert !numeric_data.temperature_changed?
91
+ assert_nil numeric_data.temperature_change
92
+ end
93
+ end
94
+
95
+ def test_nullable_integer_zero_to_string_zero_not_marked_as_changed
96
+ pirate = Pirate.new
97
+ pirate.parrot_id = 0
98
+ pirate.catchphrase = 'arrr'
99
+ assert pirate.save!
100
+
101
+ assert !pirate.changed?
102
+
103
+ pirate.parrot_id = '0'
104
+ assert !pirate.changed?
105
+ end
106
+
107
+ def test_zero_to_blank_marked_as_changed
108
+ pirate = Pirate.new
109
+ pirate.catchphrase = "Yarrrr, me hearties"
110
+ pirate.parrot_id = 1
111
+ pirate.save
112
+
113
+ # check the change from 1 to ''
114
+ pirate = Pirate.find_by_catchphrase("Yarrrr, me hearties")
115
+ pirate.parrot_id = ''
116
+ assert pirate.parrot_id_changed?
117
+ assert_equal([1, nil], pirate.parrot_id_change)
118
+ pirate.save
119
+
120
+ # check the change from nil to 0
121
+ pirate = Pirate.find_by_catchphrase("Yarrrr, me hearties")
122
+ pirate.parrot_id = 0
123
+ assert pirate.parrot_id_changed?
124
+ assert_equal([nil, 0], pirate.parrot_id_change)
125
+ pirate.save
126
+
127
+ # check the change from 0 to ''
128
+ pirate = Pirate.find_by_catchphrase("Yarrrr, me hearties")
129
+ pirate.parrot_id = ''
130
+ assert pirate.parrot_id_changed?
131
+ assert_equal([0, nil], pirate.parrot_id_change)
132
+ end
133
+
134
+ def test_object_should_be_changed_if_any_attribute_is_changed
135
+ pirate = Pirate.new
136
+ assert !pirate.changed?
137
+ assert_equal [], pirate.changed
138
+ assert_equal Hash.new, pirate.changes
139
+
140
+ pirate.catchphrase = 'arrr'
141
+ assert pirate.changed?
142
+ assert_nil pirate.catchphrase_was
143
+ assert_equal %w(catchphrase), pirate.changed
144
+ assert_equal({'catchphrase' => [nil, 'arrr']}, pirate.changes)
145
+
146
+ pirate.save
147
+ assert !pirate.changed?
148
+ assert_equal [], pirate.changed
149
+ assert_equal Hash.new, pirate.changes
150
+ end
151
+
152
+ def test_attribute_will_change!
153
+ pirate = Pirate.create!(:catchphrase => 'arr')
154
+
155
+ pirate.catchphrase << ' matey'
156
+ assert !pirate.catchphrase_changed?
157
+
158
+ assert pirate.catchphrase_will_change!
159
+ assert pirate.catchphrase_changed?
160
+ assert_equal ['arr matey', 'arr matey'], pirate.catchphrase_change
161
+
162
+ pirate.catchphrase << '!'
163
+ assert pirate.catchphrase_changed?
164
+ assert_equal ['arr matey', 'arr matey!'], pirate.catchphrase_change
165
+ end
166
+
167
+ def test_association_assignment_changes_foreign_key
168
+ pirate = Pirate.create!(:catchphrase => 'jarl')
169
+ pirate.parrot = Parrot.create!(:name => 'Lorre')
170
+ assert pirate.changed?
171
+ assert_equal %w(parrot_id), pirate.changed
172
+ end
173
+
174
+ def test_attribute_should_be_compared_with_type_cast
175
+ topic = Topic.new
176
+ assert topic.approved?
177
+ assert !topic.approved_changed?
178
+
179
+ # Coming from web form.
180
+ params = {:topic => {:approved => 1}}
181
+ # In the controller.
182
+ topic.attributes = params[:topic]
183
+ assert topic.approved?
184
+ assert !topic.approved_changed?
185
+ end
186
+
187
+ def test_partial_update
188
+ pirate = Pirate.new(:catchphrase => 'foo')
189
+ old_updated_on = 1.hour.ago.beginning_of_day
190
+
191
+ with_partial_updates Pirate, false do
192
+ assert_queries(2) { 2.times { pirate.save! } }
193
+ Pirate.update_all({ :updated_on => old_updated_on }, :id => pirate.id)
194
+ end
195
+
196
+ with_partial_updates Pirate, true do
197
+ assert_queries(0) { 2.times { pirate.save! } }
198
+ assert_equal old_updated_on, pirate.reload.updated_on
199
+
200
+ assert_queries(1) { pirate.catchphrase = 'bar'; pirate.save! }
201
+ assert_not_equal old_updated_on, pirate.reload.updated_on
202
+ end
203
+ end
204
+
205
+ def test_partial_update_with_optimistic_locking
206
+ person = Person.new(:first_name => 'foo')
207
+ old_lock_version = 1
208
+
209
+ with_partial_updates Person, false do
210
+ assert_queries(2) { 2.times { person.save! } }
211
+ Person.update_all({ :first_name => 'baz' }, :id => person.id)
212
+ end
213
+
214
+ with_partial_updates Person, true do
215
+ assert_queries(0) { 2.times { person.save! } }
216
+ assert_equal old_lock_version, person.reload.lock_version
217
+
218
+ assert_queries(1) { person.first_name = 'bar'; person.save! }
219
+ assert_not_equal old_lock_version, person.reload.lock_version
220
+ end
221
+ end
222
+
223
+ def test_changed_attributes_should_be_preserved_if_save_failure
224
+ pirate = Pirate.new
225
+ pirate.parrot_id = 1
226
+ assert !pirate.save
227
+ check_pirate_after_save_failure(pirate)
228
+
229
+ pirate = Pirate.new
230
+ pirate.parrot_id = 1
231
+ assert_raise(ActiveRecord::RecordInvalid) { pirate.save! }
232
+ check_pirate_after_save_failure(pirate)
233
+ end
234
+
235
+ def test_reload_should_clear_changed_attributes
236
+ pirate = Pirate.create!(:catchphrase => "shiver me timbers")
237
+ pirate.catchphrase = "*hic*"
238
+ assert pirate.changed?
239
+ pirate.reload
240
+ assert !pirate.changed?
241
+ end
242
+
243
+ def test_reverted_changes_are_not_dirty
244
+ phrase = "shiver me timbers"
245
+ pirate = Pirate.create!(:catchphrase => phrase)
246
+ pirate.catchphrase = "*hic*"
247
+ assert pirate.changed?
248
+ pirate.catchphrase = phrase
249
+ assert !pirate.changed?
250
+ end
251
+
252
+ def test_reverted_changes_are_not_dirty_after_multiple_changes
253
+ phrase = "shiver me timbers"
254
+ pirate = Pirate.create!(:catchphrase => phrase)
255
+ 10.times do |i|
256
+ pirate.catchphrase = "*hic*" * i
257
+ assert pirate.changed?
258
+ end
259
+ assert pirate.changed?
260
+ pirate.catchphrase = phrase
261
+ assert !pirate.changed?
262
+ end
263
+
264
+
265
+ def test_reverted_changes_are_not_dirty_going_from_nil_to_value_and_back
266
+ pirate = Pirate.create!(:catchphrase => "Yar!")
267
+
268
+ pirate.parrot_id = 1
269
+ assert pirate.changed?
270
+ assert pirate.parrot_id_changed?
271
+ assert !pirate.catchphrase_changed?
272
+
273
+ pirate.parrot_id = nil
274
+ assert !pirate.changed?
275
+ assert !pirate.parrot_id_changed?
276
+ assert !pirate.catchphrase_changed?
277
+ end
278
+
279
+ def test_save_should_store_serialized_attributes_even_with_partial_updates
280
+ with_partial_updates(Topic) do
281
+ topic = Topic.create!(:content => {:a => "a"})
282
+ topic.content[:b] = "b"
283
+ #assert topic.changed? # Known bug, will fail
284
+ topic.save!
285
+ assert_equal "b", topic.content[:b]
286
+ topic.reload
287
+ assert_equal "b", topic.content[:b]
288
+ end
289
+ end
290
+
291
+ def test_save_should_not_save_serialized_attribute_with_partial_updates_if_not_present
292
+ with_partial_updates(Topic) do
293
+ Topic.create!(:author_name => 'Bill', :content => {:a => "a"})
294
+ topic = Topic.first(:select => 'id, author_name')
295
+ topic.update_attribute :author_name, 'John'
296
+ topic = Topic.first
297
+ assert_not_nil topic.content
298
+ end
299
+ end
300
+
301
+ private
302
+ def with_partial_updates(klass, on = true)
303
+ old = klass.partial_updates?
304
+ klass.partial_updates = on
305
+ yield
306
+ ensure
307
+ klass.partial_updates = old
308
+ end
309
+
310
+ def check_pirate_after_save_failure(pirate)
311
+ assert pirate.changed?
312
+ assert pirate.parrot_id_changed?
313
+ assert_equal %w(parrot_id), pirate.changed
314
+ assert_nil pirate.parrot_id_was
315
+ end
316
+ end
@@ -0,0 +1,76 @@
1
+ require "cases/helper"
2
+ require 'models/topic'
3
+
4
+ class FinderRespondToTest < ActiveRecord::TestCase
5
+
6
+ fixtures :topics
7
+
8
+ def test_should_preserve_normal_respond_to_behaviour_and_respond_to_newly_added_method
9
+ class << Topic; self; end.send(:define_method, :method_added_for_finder_respond_to_test) { }
10
+ assert Topic.respond_to?(:method_added_for_finder_respond_to_test)
11
+ ensure
12
+ class << Topic; self; end.send(:remove_method, :method_added_for_finder_respond_to_test)
13
+ end
14
+
15
+ def test_should_preserve_normal_respond_to_behaviour_and_respond_to_standard_object_method
16
+ assert Topic.respond_to?(:to_s)
17
+ end
18
+
19
+ def test_should_respond_to_find_by_one_attribute_before_caching
20
+ ensure_topic_method_is_not_cached(:find_by_title)
21
+ assert Topic.respond_to?(:find_by_title)
22
+ end
23
+
24
+ def test_should_respond_to_find_all_by_one_attribute
25
+ ensure_topic_method_is_not_cached(:find_all_by_title)
26
+ assert Topic.respond_to?(:find_all_by_title)
27
+ end
28
+
29
+ def test_should_respond_to_find_all_by_two_attributes
30
+ ensure_topic_method_is_not_cached(:find_all_by_title_and_author_name)
31
+ assert Topic.respond_to?(:find_all_by_title_and_author_name)
32
+ end
33
+
34
+ def test_should_respond_to_find_by_two_attributes
35
+ ensure_topic_method_is_not_cached(:find_by_title_and_author_name)
36
+ assert Topic.respond_to?(:find_by_title_and_author_name)
37
+ end
38
+
39
+ def test_should_respond_to_find_or_initialize_from_one_attribute
40
+ ensure_topic_method_is_not_cached(:find_or_initialize_by_title)
41
+ assert Topic.respond_to?(:find_or_initialize_by_title)
42
+ end
43
+
44
+ def test_should_respond_to_find_or_initialize_from_two_attributes
45
+ ensure_topic_method_is_not_cached(:find_or_initialize_by_title_and_author_name)
46
+ assert Topic.respond_to?(:find_or_initialize_by_title_and_author_name)
47
+ end
48
+
49
+ def test_should_respond_to_find_or_create_from_one_attribute
50
+ ensure_topic_method_is_not_cached(:find_or_create_by_title)
51
+ assert Topic.respond_to?(:find_or_create_by_title)
52
+ end
53
+
54
+ def test_should_respond_to_find_or_create_from_two_attributes
55
+ ensure_topic_method_is_not_cached(:find_or_create_by_title_and_author_name)
56
+ assert Topic.respond_to?(:find_or_create_by_title_and_author_name)
57
+ end
58
+
59
+ def test_should_not_respond_to_find_by_one_missing_attribute
60
+ assert !Topic.respond_to?(:find_by_undertitle)
61
+ end
62
+
63
+ def test_should_not_respond_to_find_by_invalid_method_syntax
64
+ assert !Topic.respond_to?(:fail_to_find_by_title)
65
+ assert !Topic.respond_to?(:find_by_title?)
66
+ assert !Topic.respond_to?(:fail_to_find_or_create_by_title)
67
+ assert !Topic.respond_to?(:find_or_create_by_title?)
68
+ end
69
+
70
+ private
71
+
72
+ def ensure_topic_method_is_not_cached(method_id)
73
+ class << Topic; self; end.send(:remove_method, method_id) if Topic.public_methods.any? { |m| m.to_s == method_id.to_s }
74
+ end
75
+
76
+ end