activerecord_csi 2.3.5.p6

Sign up to get free protection for your applications and to get access to all the features.
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,197 @@
1
+ require 'singleton'
2
+ require 'set'
3
+
4
+ module ActiveRecord
5
+ module Observing # :nodoc:
6
+ def self.included(base)
7
+ base.extend ClassMethods
8
+ end
9
+
10
+ module ClassMethods
11
+ # Activates the observers assigned. Examples:
12
+ #
13
+ # # Calls PersonObserver.instance
14
+ # ActiveRecord::Base.observers = :person_observer
15
+ #
16
+ # # Calls Cacher.instance and GarbageCollector.instance
17
+ # ActiveRecord::Base.observers = :cacher, :garbage_collector
18
+ #
19
+ # # Same as above, just using explicit class references
20
+ # ActiveRecord::Base.observers = Cacher, GarbageCollector
21
+ #
22
+ # Note: Setting this does not instantiate the observers yet. +instantiate_observers+ is
23
+ # called during startup, and before each development request.
24
+ def observers=(*observers)
25
+ @observers = observers.flatten
26
+ end
27
+
28
+ # Gets the current observers.
29
+ def observers
30
+ @observers ||= []
31
+ end
32
+
33
+ # Instantiate the global Active Record observers.
34
+ def instantiate_observers
35
+ return if @observers.blank?
36
+ @observers.each do |observer|
37
+ if observer.respond_to?(:to_sym) # Symbol or String
38
+ observer.to_s.camelize.constantize.instance
39
+ elsif observer.respond_to?(:instance)
40
+ observer.instance
41
+ else
42
+ raise ArgumentError, "#{observer} must be a lowercase, underscored class name (or an instance of the class itself) responding to the instance method. Example: Person.observers = :big_brother # calls BigBrother.instance"
43
+ end
44
+ end
45
+ end
46
+
47
+ protected
48
+ # Notify observers when the observed class is subclassed.
49
+ def inherited(subclass)
50
+ super
51
+ changed
52
+ notify_observers :observed_class_inherited, subclass
53
+ end
54
+ end
55
+ end
56
+
57
+ # Observer classes respond to lifecycle callbacks to implement trigger-like
58
+ # behavior outside the original class. This is a great way to reduce the
59
+ # clutter that normally comes when the model class is burdened with
60
+ # functionality that doesn't pertain to the core responsibility of the
61
+ # class. Example:
62
+ #
63
+ # class CommentObserver < ActiveRecord::Observer
64
+ # def after_save(comment)
65
+ # Notifications.deliver_comment("admin@do.com", "New comment was posted", comment)
66
+ # end
67
+ # end
68
+ #
69
+ # This Observer sends an email when a Comment#save is finished.
70
+ #
71
+ # class ContactObserver < ActiveRecord::Observer
72
+ # def after_create(contact)
73
+ # contact.logger.info('New contact added!')
74
+ # end
75
+ #
76
+ # def after_destroy(contact)
77
+ # contact.logger.warn("Contact with an id of #{contact.id} was destroyed!")
78
+ # end
79
+ # end
80
+ #
81
+ # This Observer uses logger to log when specific callbacks are triggered.
82
+ #
83
+ # == Observing a class that can't be inferred
84
+ #
85
+ # Observers will by default be mapped to the class with which they share a name. So CommentObserver will
86
+ # be tied to observing Comment, ProductManagerObserver to ProductManager, and so on. If you want to name your observer
87
+ # differently than the class you're interested in observing, you can use the Observer.observe class method which takes
88
+ # either the concrete class (Product) or a symbol for that class (:product):
89
+ #
90
+ # class AuditObserver < ActiveRecord::Observer
91
+ # observe :account
92
+ #
93
+ # def after_update(account)
94
+ # AuditTrail.new(account, "UPDATED")
95
+ # end
96
+ # end
97
+ #
98
+ # If the audit observer needs to watch more than one kind of object, this can be specified with multiple arguments:
99
+ #
100
+ # class AuditObserver < ActiveRecord::Observer
101
+ # observe :account, :balance
102
+ #
103
+ # def after_update(record)
104
+ # AuditTrail.new(record, "UPDATED")
105
+ # end
106
+ # end
107
+ #
108
+ # The AuditObserver will now act on both updates to Account and Balance by treating them both as records.
109
+ #
110
+ # == Available callback methods
111
+ #
112
+ # The observer can implement callback methods for each of the methods described in the Callbacks module.
113
+ #
114
+ # == Storing Observers in Rails
115
+ #
116
+ # If you're using Active Record within Rails, observer classes are usually stored in app/models with the
117
+ # naming convention of app/models/audit_observer.rb.
118
+ #
119
+ # == Configuration
120
+ #
121
+ # In order to activate an observer, list it in the <tt>config.active_record.observers</tt> configuration setting in your
122
+ # <tt>config/environment.rb</tt> file.
123
+ #
124
+ # config.active_record.observers = :comment_observer, :signup_observer
125
+ #
126
+ # Observers will not be invoked unless you define these in your application configuration.
127
+ #
128
+ # == Loading
129
+ #
130
+ # Observers register themselves in the model class they observe, since it is the class that
131
+ # notifies them of events when they occur. As a side-effect, when an observer is loaded its
132
+ # corresponding model class is loaded.
133
+ #
134
+ # Up to (and including) Rails 2.0.2 observers were instantiated between plugins and
135
+ # application initializers. Now observers are loaded after application initializers,
136
+ # so observed models can make use of extensions.
137
+ #
138
+ # If by any chance you are using observed models in the initialization you can still
139
+ # load their observers by calling <tt>ModelObserver.instance</tt> before. Observers are
140
+ # singletons and that call instantiates and registers them.
141
+ #
142
+ class Observer
143
+ include Singleton
144
+
145
+ class << self
146
+ # Attaches the observer to the supplied model classes.
147
+ def observe(*models)
148
+ models.flatten!
149
+ models.collect! { |model| model.is_a?(Symbol) ? model.to_s.camelize.constantize : model }
150
+ define_method(:observed_classes) { Set.new(models) }
151
+ end
152
+
153
+ # The class observed by default is inferred from the observer's class name:
154
+ # assert_equal Person, PersonObserver.observed_class
155
+ def observed_class
156
+ if observed_class_name = name[/(.*)Observer/, 1]
157
+ observed_class_name.constantize
158
+ else
159
+ nil
160
+ end
161
+ end
162
+ end
163
+
164
+ # Start observing the declared classes and their subclasses.
165
+ def initialize
166
+ Set.new(observed_classes + observed_subclasses).each { |klass| add_observer! klass }
167
+ end
168
+
169
+ # Send observed_method(object) if the method exists.
170
+ def update(observed_method, object) #:nodoc:
171
+ send(observed_method, object) if respond_to?(observed_method)
172
+ end
173
+
174
+ # Special method sent by the observed class when it is inherited.
175
+ # Passes the new subclass.
176
+ def observed_class_inherited(subclass) #:nodoc:
177
+ self.class.observe(observed_classes + [subclass])
178
+ add_observer!(subclass)
179
+ end
180
+
181
+ protected
182
+ def observed_classes
183
+ Set.new([self.class.observed_class].compact.flatten)
184
+ end
185
+
186
+ def observed_subclasses
187
+ observed_classes.sum([]) { |klass| klass.send(:subclasses) }
188
+ end
189
+
190
+ def add_observer!(klass)
191
+ klass.add_observer(self)
192
+ if respond_to?(:after_find) && !klass.method_defined?(:after_find)
193
+ klass.class_eval 'def after_find() end'
194
+ end
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,33 @@
1
+ module ActiveRecord
2
+ class QueryCache
3
+ module ClassMethods
4
+ # Enable the query cache within the block if Active Record is configured.
5
+ def cache(&block)
6
+ if ActiveRecord::Base.configurations.blank?
7
+ yield
8
+ else
9
+ connection.cache(&block)
10
+ end
11
+ end
12
+
13
+ # Disable the query cache within the block if Active Record is configured.
14
+ def uncached(&block)
15
+ if ActiveRecord::Base.configurations.blank?
16
+ yield
17
+ else
18
+ connection.uncached(&block)
19
+ end
20
+ end
21
+ end
22
+
23
+ def initialize(app)
24
+ @app = app
25
+ end
26
+
27
+ def call(env)
28
+ ActiveRecord::Base.cache do
29
+ @app.call(env)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,320 @@
1
+ module ActiveRecord
2
+ module Reflection # :nodoc:
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ # Reflection allows you to interrogate Active Record classes and objects about their associations and aggregations.
8
+ # This information can, for example, be used in a form builder that took an Active Record object and created input
9
+ # fields for all of the attributes depending on their type and displayed the associations to other objects.
10
+ #
11
+ # You can find the interface for the AggregateReflection and AssociationReflection classes in the abstract MacroReflection class.
12
+ module ClassMethods
13
+ def create_reflection(macro, name, options, active_record)
14
+ case macro
15
+ when :has_many, :belongs_to, :has_one, :has_and_belongs_to_many
16
+ klass = options[:through] ? ThroughReflection : AssociationReflection
17
+ reflection = klass.new(macro, name, options, active_record)
18
+ when :composed_of
19
+ reflection = AggregateReflection.new(macro, name, options, active_record)
20
+ end
21
+ write_inheritable_hash :reflections, name => reflection
22
+ reflection
23
+ end
24
+
25
+ # Returns a hash containing all AssociationReflection objects for the current class
26
+ # Example:
27
+ #
28
+ # Invoice.reflections
29
+ # Account.reflections
30
+ #
31
+ def reflections
32
+ read_inheritable_attribute(:reflections) || write_inheritable_attribute(:reflections, {})
33
+ end
34
+
35
+ # Returns an array of AggregateReflection objects for all the aggregations in the class.
36
+ def reflect_on_all_aggregations
37
+ reflections.values.select { |reflection| reflection.is_a?(AggregateReflection) }
38
+ end
39
+
40
+ # Returns the AggregateReflection object for the named +aggregation+ (use the symbol). Example:
41
+ #
42
+ # Account.reflect_on_aggregation(:balance) # returns the balance AggregateReflection
43
+ #
44
+ def reflect_on_aggregation(aggregation)
45
+ reflections[aggregation].is_a?(AggregateReflection) ? reflections[aggregation] : nil
46
+ end
47
+
48
+ # Returns an array of AssociationReflection objects for all the associations in the class. If you only want to reflect on a
49
+ # certain association type, pass in the symbol (<tt>:has_many</tt>, <tt>:has_one</tt>, <tt>:belongs_to</tt>) for that as the first parameter.
50
+ # Example:
51
+ #
52
+ # Account.reflect_on_all_associations # returns an array of all associations
53
+ # Account.reflect_on_all_associations(:has_many) # returns an array of all has_many associations
54
+ #
55
+ def reflect_on_all_associations(macro = nil)
56
+ association_reflections = reflections.values.select { |reflection| reflection.is_a?(AssociationReflection) }
57
+ macro ? association_reflections.select { |reflection| reflection.macro == macro } : association_reflections
58
+ end
59
+
60
+ # Returns the AssociationReflection object for the named +association+ (use the symbol). Example:
61
+ #
62
+ # Account.reflect_on_association(:owner) # returns the owner AssociationReflection
63
+ # Invoice.reflect_on_association(:line_items).macro # returns :has_many
64
+ #
65
+ def reflect_on_association(association)
66
+ reflections[association].is_a?(AssociationReflection) ? reflections[association] : nil
67
+ end
68
+
69
+ # Returns an array of AssociationReflection objects for all associations which have <tt>:autosave</tt> enabled.
70
+ def reflect_on_all_autosave_associations
71
+ reflections.values.select { |reflection| reflection.options[:autosave] }
72
+ end
73
+ end
74
+
75
+
76
+ # Abstract base class for AggregateReflection and AssociationReflection that describes the interface available for both of
77
+ # those classes. Objects of AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods.
78
+ class MacroReflection
79
+ attr_reader :active_record
80
+
81
+ def initialize(macro, name, options, active_record)
82
+ @macro, @name, @options, @active_record = macro, name, options, active_record
83
+ end
84
+
85
+ # Returns the name of the macro. For example, <tt>composed_of :balance, :class_name => 'Money'</tt> will return
86
+ # <tt>:balance</tt> or for <tt>has_many :clients</tt> it will return <tt>:clients</tt>.
87
+ def name
88
+ @name
89
+ end
90
+
91
+ # Returns the macro type. For example, <tt>composed_of :balance, :class_name => 'Money'</tt> will return <tt>:composed_of</tt>
92
+ # or for <tt>has_many :clients</tt> will return <tt>:has_many</tt>.
93
+ def macro
94
+ @macro
95
+ end
96
+
97
+ # Returns the hash of options used for the macro. For example, it would return <tt>{ :class_name => "Money" }</tt> for
98
+ # <tt>composed_of :balance, :class_name => 'Money'</tt> or +{}+ for <tt>has_many :clients</tt>.
99
+ def options
100
+ @options
101
+ end
102
+
103
+ # Returns the class for the macro. For example, <tt>composed_of :balance, :class_name => 'Money'</tt> returns the Money
104
+ # class and <tt>has_many :clients</tt> returns the Client class.
105
+ def klass
106
+ @klass ||= class_name.constantize
107
+ end
108
+
109
+ # Returns the class name for the macro. For example, <tt>composed_of :balance, :class_name => 'Money'</tt> returns <tt>'Money'</tt>
110
+ # and <tt>has_many :clients</tt> returns <tt>'Client'</tt>.
111
+ def class_name
112
+ @class_name ||= options[:class_name] || derive_class_name
113
+ end
114
+
115
+ # Returns +true+ if +self+ and +other_aggregation+ have the same +name+ attribute, +active_record+ attribute,
116
+ # and +other_aggregation+ has an options hash assigned to it.
117
+ def ==(other_aggregation)
118
+ other_aggregation.kind_of?(self.class) && name == other_aggregation.name && other_aggregation.options && active_record == other_aggregation.active_record
119
+ end
120
+
121
+ def sanitized_conditions #:nodoc:
122
+ @sanitized_conditions ||= klass.send(:sanitize_sql, options[:conditions]) if options[:conditions]
123
+ end
124
+
125
+ # Returns +true+ if +self+ is a +belongs_to+ reflection.
126
+ def belongs_to?
127
+ macro == :belongs_to
128
+ end
129
+
130
+ private
131
+ def derive_class_name
132
+ name.to_s.camelize
133
+ end
134
+ end
135
+
136
+
137
+ # Holds all the meta-data about an aggregation as it was specified in the Active Record class.
138
+ class AggregateReflection < MacroReflection #:nodoc:
139
+ end
140
+
141
+ # Holds all the meta-data about an association as it was specified in the Active Record class.
142
+ class AssociationReflection < MacroReflection #:nodoc:
143
+ # Returns the target association's class:
144
+ #
145
+ # class Author < ActiveRecord::Base
146
+ # has_many :books
147
+ # end
148
+ #
149
+ # Author.reflect_on_association(:books).klass
150
+ # # => Book
151
+ #
152
+ # <b>Note:</b> do not call +klass.new+ or +klass.create+ to instantiate
153
+ # a new association object. Use +build_association+ or +create_association+
154
+ # instead. This allows plugins to hook into association object creation.
155
+ def klass
156
+ @klass ||= active_record.send(:compute_type, class_name)
157
+ end
158
+
159
+ # Returns a new, unsaved instance of the associated class. +options+ will
160
+ # be passed to the class's constructor.
161
+ def build_association(*options)
162
+ klass.new(*options)
163
+ end
164
+
165
+ # Creates a new instance of the associated class, and immediates saves it
166
+ # with ActiveRecord::Base#save. +options+ will be passed to the class's
167
+ # creation method. Returns the newly created object.
168
+ def create_association(*options)
169
+ klass.create(*options)
170
+ end
171
+
172
+ # Creates a new instance of the associated class, and immediates saves it
173
+ # with ActiveRecord::Base#save!. +options+ will be passed to the class's
174
+ # creation method. If the created record doesn't pass validations, then an
175
+ # exception will be raised.
176
+ #
177
+ # Returns the newly created object.
178
+ def create_association!(*options)
179
+ klass.create!(*options)
180
+ end
181
+
182
+ def table_name
183
+ @table_name ||= klass.table_name
184
+ end
185
+
186
+ def quoted_table_name
187
+ @quoted_table_name ||= klass.quoted_table_name
188
+ end
189
+
190
+ def primary_key_name
191
+ @primary_key_name ||= options[:foreign_key] || derive_primary_key_name
192
+ end
193
+
194
+ def association_foreign_key
195
+ @association_foreign_key ||= @options[:association_foreign_key] || class_name.foreign_key
196
+ end
197
+
198
+ def counter_cache_column
199
+ if options[:counter_cache] == true
200
+ "#{active_record.name.demodulize.underscore.pluralize}_count"
201
+ elsif options[:counter_cache]
202
+ options[:counter_cache]
203
+ end
204
+ end
205
+
206
+ def columns(tbl_name, log_msg)
207
+ @columns ||= klass.connection.columns(tbl_name, log_msg)
208
+ end
209
+
210
+ def reset_column_information
211
+ @columns = nil
212
+ end
213
+
214
+ def check_validity!
215
+ end
216
+
217
+ def through_reflection
218
+ false
219
+ end
220
+
221
+ def through_reflection_primary_key_name
222
+ end
223
+
224
+ def source_reflection
225
+ nil
226
+ end
227
+
228
+ private
229
+ def derive_class_name
230
+ class_name = name.to_s.camelize
231
+ class_name = class_name.singularize if [ :has_many, :has_and_belongs_to_many ].include?(macro)
232
+ class_name
233
+ end
234
+
235
+ def derive_primary_key_name
236
+ if belongs_to?
237
+ "#{name}_id"
238
+ elsif options[:as]
239
+ "#{options[:as]}_id"
240
+ else
241
+ active_record.name.foreign_key
242
+ end
243
+ end
244
+ end
245
+
246
+ # Holds all the meta-data about a :through association as it was specified in the Active Record class.
247
+ class ThroughReflection < AssociationReflection #:nodoc:
248
+ # Gets the source of the through reflection. It checks both a singularized and pluralized form for <tt>:belongs_to</tt> or <tt>:has_many</tt>.
249
+ # (The <tt>:tags</tt> association on Tagging below.)
250
+ #
251
+ # class Post < ActiveRecord::Base
252
+ # has_many :taggings
253
+ # has_many :tags, :through => :taggings
254
+ # end
255
+ #
256
+ def source_reflection
257
+ @source_reflection ||= source_reflection_names.collect { |name| through_reflection.klass.reflect_on_association(name) }.compact.first
258
+ end
259
+
260
+ # Returns the AssociationReflection object specified in the <tt>:through</tt> option
261
+ # of a HasManyThrough or HasOneThrough association. Example:
262
+ #
263
+ # class Post < ActiveRecord::Base
264
+ # has_many :taggings
265
+ # has_many :tags, :through => :taggings
266
+ # end
267
+ #
268
+ # tags_reflection = Post.reflect_on_association(:tags)
269
+ # taggings_reflection = tags_reflection.through_reflection
270
+ #
271
+ def through_reflection
272
+ @through_reflection ||= active_record.reflect_on_association(options[:through])
273
+ end
274
+
275
+ # Gets an array of possible <tt>:through</tt> source reflection names:
276
+ #
277
+ # [:singularized, :pluralized]
278
+ #
279
+ def source_reflection_names
280
+ @source_reflection_names ||= (options[:source] ? [options[:source]] : [name.to_s.singularize, name]).collect { |n| n.to_sym }
281
+ end
282
+
283
+ def check_validity!
284
+ if through_reflection.nil?
285
+ raise HasManyThroughAssociationNotFoundError.new(active_record.name, self)
286
+ end
287
+
288
+ if source_reflection.nil?
289
+ raise HasManyThroughSourceAssociationNotFoundError.new(self)
290
+ end
291
+
292
+ if options[:source_type] && source_reflection.options[:polymorphic].nil?
293
+ raise HasManyThroughAssociationPointlessSourceTypeError.new(active_record.name, self, source_reflection)
294
+ end
295
+
296
+ if source_reflection.options[:polymorphic] && options[:source_type].nil?
297
+ raise HasManyThroughAssociationPolymorphicError.new(active_record.name, self, source_reflection)
298
+ end
299
+
300
+ unless [:belongs_to, :has_many, :has_one].include?(source_reflection.macro) && source_reflection.options[:through].nil?
301
+ raise HasManyThroughSourceAssociationMacroError.new(self)
302
+ end
303
+ end
304
+
305
+ def through_reflection_primary_key
306
+ through_reflection.belongs_to? ? through_reflection.klass.primary_key : through_reflection.primary_key_name
307
+ end
308
+
309
+ def through_reflection_primary_key_name
310
+ through_reflection.primary_key_name if through_reflection.belongs_to?
311
+ end
312
+
313
+ private
314
+ def derive_class_name
315
+ # get the class_name of the belongs_to association of the through reflection
316
+ options[:source_type] || source_reflection.class_name
317
+ end
318
+ end
319
+ end
320
+ end
@@ -0,0 +1,51 @@
1
+ module ActiveRecord
2
+ # Allows programmers to programmatically define a schema in a portable
3
+ # DSL. This means you can define tables, indexes, etc. without using SQL
4
+ # directly, so your applications can more easily support multiple
5
+ # databases.
6
+ #
7
+ # Usage:
8
+ #
9
+ # ActiveRecord::Schema.define do
10
+ # create_table :authors do |t|
11
+ # t.string :name, :null => false
12
+ # end
13
+ #
14
+ # add_index :authors, :name, :unique
15
+ #
16
+ # create_table :posts do |t|
17
+ # t.integer :author_id, :null => false
18
+ # t.string :subject
19
+ # t.text :body
20
+ # t.boolean :private, :default => false
21
+ # end
22
+ #
23
+ # add_index :posts, :author_id
24
+ # end
25
+ #
26
+ # ActiveRecord::Schema is only supported by database adapters that also
27
+ # support migrations, the two features being very similar.
28
+ class Schema < Migration
29
+ private_class_method :new
30
+
31
+ # Eval the given block. All methods available to the current connection
32
+ # adapter are available within the block, so you can easily use the
33
+ # database definition DSL to build up your schema (+create_table+,
34
+ # +add_index+, etc.).
35
+ #
36
+ # The +info+ hash is optional, and if given is used to define metadata
37
+ # about the current schema (currently, only the schema's version):
38
+ #
39
+ # ActiveRecord::Schema.define(:version => 20380119000001) do
40
+ # ...
41
+ # end
42
+ def self.define(info={}, &block)
43
+ instance_eval(&block)
44
+
45
+ unless info[:version].blank?
46
+ initialize_schema_migrations_table
47
+ assume_migrated_upto_version info[:version]
48
+ end
49
+ end
50
+ end
51
+ end