3mix-castronaut 0.5.0.2

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 (904) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.textile +75 -0
  3. data/Rakefile +105 -0
  4. data/app/config.rb +15 -0
  5. data/app/config.ru +24 -0
  6. data/app/controllers/application.rb +47 -0
  7. data/app/public/javascripts/application.js +3 -0
  8. data/app/public/javascripts/jquery.js +32 -0
  9. data/app/public/stylesheets/screen.css +122 -0
  10. data/app/views/layout.erb +27 -0
  11. data/app/views/login.erb +31 -0
  12. data/app/views/logout.erb +13 -0
  13. data/app/views/proxy_validate.erb +25 -0
  14. data/app/views/service_validate.erb +18 -0
  15. data/bin/castronaut +48 -0
  16. data/castronaut.rb +7 -0
  17. data/config/castronaut.example.yml +47 -0
  18. data/config/nginx_vhost.conf +24 -0
  19. data/config/thin_config.yml +13 -0
  20. data/lib/castronaut/adapters/active_record_adapter.rb +20 -0
  21. data/lib/castronaut/adapters/development/adapter.rb +13 -0
  22. data/lib/castronaut/adapters/development/user.rb +25 -0
  23. data/lib/castronaut/adapters/ldap/adapter.rb +15 -0
  24. data/lib/castronaut/adapters/ldap/user.rb +40 -0
  25. data/lib/castronaut/adapters/restful_authentication/adapter.rb +21 -0
  26. data/lib/castronaut/adapters/restful_authentication/user.rb +50 -0
  27. data/lib/castronaut/adapters.rb +17 -0
  28. data/lib/castronaut/authentication_result.rb +27 -0
  29. data/lib/castronaut/configuration.rb +95 -0
  30. data/lib/castronaut/db/001_create_cas_database.rb +47 -0
  31. data/lib/castronaut/db/002_change_username_to_identifier.rb +11 -0
  32. data/lib/castronaut/db/003_add_extra_info.rb +11 -0
  33. data/lib/castronaut/models/consumeable.rb +18 -0
  34. data/lib/castronaut/models/dispenser.rb +14 -0
  35. data/lib/castronaut/models/login_ticket.rb +53 -0
  36. data/lib/castronaut/models/proxy_granting_ticket.rb +69 -0
  37. data/lib/castronaut/models/proxy_ticket.rb +43 -0
  38. data/lib/castronaut/models/service_ticket.rb +100 -0
  39. data/lib/castronaut/models/ticket_granting_ticket.rb +70 -0
  40. data/lib/castronaut/presenters/base.rb +32 -0
  41. data/lib/castronaut/presenters/login.rb +60 -0
  42. data/lib/castronaut/presenters/logout.rb +40 -0
  43. data/lib/castronaut/presenters/process_login.rb +127 -0
  44. data/lib/castronaut/presenters/proxy_validate.rb +49 -0
  45. data/lib/castronaut/presenters/service_validate.rb +43 -0
  46. data/lib/castronaut/ticket_result.rb +27 -0
  47. data/lib/castronaut/utilities/random_string.rb +24 -0
  48. data/lib/castronaut.rb +34 -0
  49. data/lib/version.rb +5 -0
  50. data/spec/app/controllers/application_spec.rb +89 -0
  51. data/spec/castronaut/adapters/development/adapter_spec.rb +14 -0
  52. data/spec/castronaut/adapters/development/user_spec.rb +55 -0
  53. data/spec/castronaut/adapters/ldap/adapter_spec.rb +14 -0
  54. data/spec/castronaut/adapters/ldap/user_spec.rb +25 -0
  55. data/spec/castronaut/adapters/restful_authentication/adapter_spec.rb +14 -0
  56. data/spec/castronaut/adapters/restful_authentication/user_spec.rb +108 -0
  57. data/spec/castronaut/adapters_spec.rb +13 -0
  58. data/spec/castronaut/authentication_result_spec.rb +20 -0
  59. data/spec/castronaut/configuration_spec.rb +172 -0
  60. data/spec/castronaut/models/consumeable_spec.rb +39 -0
  61. data/spec/castronaut/models/dispenser_spec.rb +30 -0
  62. data/spec/castronaut/models/login_ticket_spec.rb +107 -0
  63. data/spec/castronaut/models/proxy_granting_ticket_spec.rb +302 -0
  64. data/spec/castronaut/models/proxy_ticket_spec.rb +109 -0
  65. data/spec/castronaut/models/service_ticket_spec.rb +269 -0
  66. data/spec/castronaut/models/ticket_granting_ticket_spec.rb +89 -0
  67. data/spec/castronaut/presenters/login_spec.rb +152 -0
  68. data/spec/castronaut/presenters/logout_spec.rb +85 -0
  69. data/spec/castronaut/presenters/process_login_spec.rb +300 -0
  70. data/spec/castronaut/presenters/proxy_validate_spec.rb +103 -0
  71. data/spec/castronaut/presenters/service_validate_spec.rb +86 -0
  72. data/spec/castronaut/ticket_result_spec.rb +42 -0
  73. data/spec/castronaut/utilities/random_string_spec.rb +14 -0
  74. data/spec/castronaut_spec.rb +26 -0
  75. data/spec/spec.opts +2 -0
  76. data/spec/spec_controller_helper.rb +17 -0
  77. data/spec/spec_helper.rb +49 -0
  78. data/spec/spec_rails_mocks.rb +132 -0
  79. data/vendor/activerecord/CHANGELOG +5753 -0
  80. data/vendor/activerecord/README +351 -0
  81. data/vendor/activerecord/RUNNING_UNIT_TESTS +36 -0
  82. data/vendor/activerecord/Rakefile +248 -0
  83. data/vendor/activerecord/examples/associations.png +0 -0
  84. data/vendor/activerecord/install.rb +30 -0
  85. data/vendor/activerecord/lib/active_record/aggregations.rb +189 -0
  86. data/vendor/activerecord/lib/active_record/association_preload.rb +282 -0
  87. data/vendor/activerecord/lib/active_record/associations/association_collection.rb +368 -0
  88. data/vendor/activerecord/lib/active_record/associations/association_proxy.rb +220 -0
  89. data/vendor/activerecord/lib/active_record/associations/belongs_to_association.rb +58 -0
  90. data/vendor/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb +49 -0
  91. data/vendor/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb +111 -0
  92. data/vendor/activerecord/lib/active_record/associations/has_many_association.rb +121 -0
  93. data/vendor/activerecord/lib/active_record/associations/has_many_through_association.rb +254 -0
  94. data/vendor/activerecord/lib/active_record/associations/has_one_association.rb +98 -0
  95. data/vendor/activerecord/lib/active_record/associations/has_one_through_association.rb +32 -0
  96. data/vendor/activerecord/lib/active_record/associations.rb +2012 -0
  97. data/vendor/activerecord/lib/active_record/attribute_methods.rb +379 -0
  98. data/vendor/activerecord/lib/active_record/base.rb +2744 -0
  99. data/vendor/activerecord/lib/active_record/calculations.rb +288 -0
  100. data/vendor/activerecord/lib/active_record/callbacks.rb +312 -0
  101. data/vendor/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb +309 -0
  102. data/vendor/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +176 -0
  103. data/vendor/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb +93 -0
  104. data/vendor/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb +69 -0
  105. data/vendor/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +664 -0
  106. data/vendor/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +428 -0
  107. data/vendor/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +169 -0
  108. data/vendor/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +559 -0
  109. data/vendor/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +994 -0
  110. data/vendor/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -0
  111. data/vendor/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb +418 -0
  112. data/vendor/activerecord/lib/active_record/dirty.rb +165 -0
  113. data/vendor/activerecord/lib/active_record/fixtures.rb +997 -0
  114. data/vendor/activerecord/lib/active_record/locking/optimistic.rb +148 -0
  115. data/vendor/activerecord/lib/active_record/locking/pessimistic.rb +77 -0
  116. data/vendor/activerecord/lib/active_record/migration.rb +523 -0
  117. data/vendor/activerecord/lib/active_record/named_scope.rb +168 -0
  118. data/vendor/activerecord/lib/active_record/observer.rb +197 -0
  119. data/vendor/activerecord/lib/active_record/query_cache.rb +21 -0
  120. data/vendor/activerecord/lib/active_record/reflection.rb +239 -0
  121. data/vendor/activerecord/lib/active_record/schema.rb +51 -0
  122. data/vendor/activerecord/lib/active_record/schema_dumper.rb +171 -0
  123. data/vendor/activerecord/lib/active_record/serialization.rb +98 -0
  124. data/vendor/activerecord/lib/active_record/serializers/json_serializer.rb +80 -0
  125. data/vendor/activerecord/lib/active_record/serializers/xml_serializer.rb +338 -0
  126. data/vendor/activerecord/lib/active_record/test_case.rb +47 -0
  127. data/vendor/activerecord/lib/active_record/timestamp.rb +41 -0
  128. data/vendor/activerecord/lib/active_record/transactions.rb +130 -0
  129. data/vendor/activerecord/lib/active_record/validations.rb +971 -0
  130. data/vendor/activerecord/lib/active_record/vendor/mysql.rb +1214 -0
  131. data/vendor/activerecord/lib/active_record/version.rb +9 -0
  132. data/vendor/activerecord/lib/active_record.rb +80 -0
  133. data/vendor/activerecord/lib/activerecord.rb +1 -0
  134. data/vendor/activerecord/test/assets/example.log +1 -0
  135. data/vendor/activerecord/test/assets/flowers.jpg +0 -0
  136. data/vendor/activerecord/test/cases/aaa_create_tables_test.rb +24 -0
  137. data/vendor/activerecord/test/cases/active_schema_test_mysql.rb +95 -0
  138. data/vendor/activerecord/test/cases/active_schema_test_postgresql.rb +24 -0
  139. data/vendor/activerecord/test/cases/adapter_test.rb +127 -0
  140. data/vendor/activerecord/test/cases/adapter_test_sqlserver.rb +95 -0
  141. data/vendor/activerecord/test/cases/aggregations_test.rb +128 -0
  142. data/vendor/activerecord/test/cases/ar_schema_test.rb +33 -0
  143. data/vendor/activerecord/test/cases/associations/belongs_to_associations_test.rb +431 -0
  144. data/vendor/activerecord/test/cases/associations/callbacks_test.rb +161 -0
  145. data/vendor/activerecord/test/cases/associations/cascaded_eager_loading_test.rb +123 -0
  146. data/vendor/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb +36 -0
  147. data/vendor/activerecord/test/cases/associations/eager_load_nested_include_test.rb +83 -0
  148. data/vendor/activerecord/test/cases/associations/eager_singularization_test.rb +145 -0
  149. data/vendor/activerecord/test/cases/associations/eager_test.rb +636 -0
  150. data/vendor/activerecord/test/cases/associations/extension_test.rb +47 -0
  151. data/vendor/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb +706 -0
  152. data/vendor/activerecord/test/cases/associations/has_many_associations_test.rb +1034 -0
  153. data/vendor/activerecord/test/cases/associations/has_many_through_associations_test.rb +200 -0
  154. data/vendor/activerecord/test/cases/associations/has_one_associations_test.rb +345 -0
  155. data/vendor/activerecord/test/cases/associations/has_one_through_associations_test.rb +113 -0
  156. data/vendor/activerecord/test/cases/associations/inner_join_association_test.rb +88 -0
  157. data/vendor/activerecord/test/cases/associations/join_model_test.rb +714 -0
  158. data/vendor/activerecord/test/cases/associations_test.rb +262 -0
  159. data/vendor/activerecord/test/cases/attribute_methods_test.rb +238 -0
  160. data/vendor/activerecord/test/cases/base_test.rb +1997 -0
  161. data/vendor/activerecord/test/cases/binary_test.rb +34 -0
  162. data/vendor/activerecord/test/cases/calculations_test.rb +323 -0
  163. data/vendor/activerecord/test/cases/callbacks_test.rb +400 -0
  164. data/vendor/activerecord/test/cases/class_inheritable_attributes_test.rb +32 -0
  165. data/vendor/activerecord/test/cases/column_alias_test.rb +17 -0
  166. data/vendor/activerecord/test/cases/column_definition_test.rb +36 -0
  167. data/vendor/activerecord/test/cases/connection_test_firebird.rb +8 -0
  168. data/vendor/activerecord/test/cases/connection_test_mysql.rb +30 -0
  169. data/vendor/activerecord/test/cases/copy_table_test_sqlite.rb +69 -0
  170. data/vendor/activerecord/test/cases/database_statements_test.rb +12 -0
  171. data/vendor/activerecord/test/cases/datatype_test_postgresql.rb +203 -0
  172. data/vendor/activerecord/test/cases/date_time_test.rb +37 -0
  173. data/vendor/activerecord/test/cases/default_test_firebird.rb +16 -0
  174. data/vendor/activerecord/test/cases/defaults_test.rb +69 -0
  175. data/vendor/activerecord/test/cases/deprecated_finder_test.rb +30 -0
  176. data/vendor/activerecord/test/cases/dirty_test.rb +257 -0
  177. data/vendor/activerecord/test/cases/finder_respond_to_test.rb +76 -0
  178. data/vendor/activerecord/test/cases/finder_test.rb +890 -0
  179. data/vendor/activerecord/test/cases/fixtures_test.rb +626 -0
  180. data/vendor/activerecord/test/cases/helper.rb +47 -0
  181. data/vendor/activerecord/test/cases/inheritance_test.rb +262 -0
  182. data/vendor/activerecord/test/cases/invalid_date_test.rb +24 -0
  183. data/vendor/activerecord/test/cases/json_serialization_test.rb +205 -0
  184. data/vendor/activerecord/test/cases/lifecycle_test.rb +193 -0
  185. data/vendor/activerecord/test/cases/locking_test.rb +309 -0
  186. data/vendor/activerecord/test/cases/method_scoping_test.rb +462 -0
  187. data/vendor/activerecord/test/cases/migration_test.rb +1444 -0
  188. data/vendor/activerecord/test/cases/migration_test_firebird.rb +124 -0
  189. data/vendor/activerecord/test/cases/mixin_test.rb +96 -0
  190. data/vendor/activerecord/test/cases/modules_test.rb +39 -0
  191. data/vendor/activerecord/test/cases/multiple_db_test.rb +60 -0
  192. data/vendor/activerecord/test/cases/named_scope_test.rb +206 -0
  193. data/vendor/activerecord/test/cases/pk_test.rb +101 -0
  194. data/vendor/activerecord/test/cases/query_cache_test.rb +127 -0
  195. data/vendor/activerecord/test/cases/readonly_test.rb +107 -0
  196. data/vendor/activerecord/test/cases/reflection_test.rb +176 -0
  197. data/vendor/activerecord/test/cases/reserved_word_test_mysql.rb +176 -0
  198. data/vendor/activerecord/test/cases/schema_authorization_test_postgresql.rb +75 -0
  199. data/vendor/activerecord/test/cases/schema_dumper_test.rb +184 -0
  200. data/vendor/activerecord/test/cases/schema_test_postgresql.rb +102 -0
  201. data/vendor/activerecord/test/cases/serialization_test.rb +47 -0
  202. data/vendor/activerecord/test/cases/synonym_test_oracle.rb +17 -0
  203. data/vendor/activerecord/test/cases/table_name_test_sqlserver.rb +23 -0
  204. data/vendor/activerecord/test/cases/threaded_connections_test.rb +48 -0
  205. data/vendor/activerecord/test/cases/transactions_test.rb +307 -0
  206. data/vendor/activerecord/test/cases/unconnected_test.rb +32 -0
  207. data/vendor/activerecord/test/cases/validations_test.rb +1534 -0
  208. data/vendor/activerecord/test/cases/xml_serialization_test.rb +202 -0
  209. data/vendor/activerecord/test/config.rb +5 -0
  210. data/vendor/activerecord/test/connections/native_db2/connection.rb +25 -0
  211. data/vendor/activerecord/test/connections/native_firebird/connection.rb +26 -0
  212. data/vendor/activerecord/test/connections/native_frontbase/connection.rb +27 -0
  213. data/vendor/activerecord/test/connections/native_mysql/connection.rb +27 -0
  214. data/vendor/activerecord/test/connections/native_openbase/connection.rb +21 -0
  215. data/vendor/activerecord/test/connections/native_oracle/connection.rb +27 -0
  216. data/vendor/activerecord/test/connections/native_postgresql/connection.rb +21 -0
  217. data/vendor/activerecord/test/connections/native_sqlite/connection.rb +25 -0
  218. data/vendor/activerecord/test/connections/native_sqlite3/connection.rb +25 -0
  219. data/vendor/activerecord/test/connections/native_sqlite3/in_memory_connection.rb +18 -0
  220. data/vendor/activerecord/test/connections/native_sybase/connection.rb +23 -0
  221. data/vendor/activerecord/test/debug.log +358 -0
  222. data/vendor/activerecord/test/fixtures/accounts.yml +28 -0
  223. data/vendor/activerecord/test/fixtures/all/developers.yml +0 -0
  224. data/vendor/activerecord/test/fixtures/all/people.csv +0 -0
  225. data/vendor/activerecord/test/fixtures/all/tasks.yml +0 -0
  226. data/vendor/activerecord/test/fixtures/author_addresses.yml +5 -0
  227. data/vendor/activerecord/test/fixtures/author_favorites.yml +4 -0
  228. data/vendor/activerecord/test/fixtures/authors.yml +9 -0
  229. data/vendor/activerecord/test/fixtures/binaries.yml +132 -0
  230. data/vendor/activerecord/test/fixtures/books.yml +7 -0
  231. data/vendor/activerecord/test/fixtures/categories/special_categories.yml +9 -0
  232. data/vendor/activerecord/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
  233. data/vendor/activerecord/test/fixtures/categories.yml +14 -0
  234. data/vendor/activerecord/test/fixtures/categories_ordered.yml +7 -0
  235. data/vendor/activerecord/test/fixtures/categories_posts.yml +23 -0
  236. data/vendor/activerecord/test/fixtures/categorizations.yml +17 -0
  237. data/vendor/activerecord/test/fixtures/clubs.yml +6 -0
  238. data/vendor/activerecord/test/fixtures/comments.yml +59 -0
  239. data/vendor/activerecord/test/fixtures/companies.yml +55 -0
  240. data/vendor/activerecord/test/fixtures/computers.yml +4 -0
  241. data/vendor/activerecord/test/fixtures/courses.yml +7 -0
  242. data/vendor/activerecord/test/fixtures/customers.yml +17 -0
  243. data/vendor/activerecord/test/fixtures/developers.yml +21 -0
  244. data/vendor/activerecord/test/fixtures/developers_projects.yml +17 -0
  245. data/vendor/activerecord/test/fixtures/edges.yml +6 -0
  246. data/vendor/activerecord/test/fixtures/entrants.yml +14 -0
  247. data/vendor/activerecord/test/fixtures/fixture_database.sqlite3 +0 -0
  248. data/vendor/activerecord/test/fixtures/fixture_database_2.sqlite3 +0 -0
  249. data/vendor/activerecord/test/fixtures/fk_test_has_fk.yml +3 -0
  250. data/vendor/activerecord/test/fixtures/fk_test_has_pk.yml +2 -0
  251. data/vendor/activerecord/test/fixtures/funny_jokes.yml +10 -0
  252. data/vendor/activerecord/test/fixtures/items.yml +4 -0
  253. data/vendor/activerecord/test/fixtures/jobs.yml +7 -0
  254. data/vendor/activerecord/test/fixtures/legacy_things.yml +3 -0
  255. data/vendor/activerecord/test/fixtures/mateys.yml +4 -0
  256. data/vendor/activerecord/test/fixtures/members.yml +4 -0
  257. data/vendor/activerecord/test/fixtures/memberships.yml +20 -0
  258. data/vendor/activerecord/test/fixtures/minimalistics.yml +2 -0
  259. data/vendor/activerecord/test/fixtures/mixed_case_monkeys.yml +6 -0
  260. data/vendor/activerecord/test/fixtures/mixins.yml +29 -0
  261. data/vendor/activerecord/test/fixtures/movies.yml +7 -0
  262. data/vendor/activerecord/test/fixtures/naked/csv/accounts.csv +1 -0
  263. data/vendor/activerecord/test/fixtures/naked/yml/accounts.yml +1 -0
  264. data/vendor/activerecord/test/fixtures/naked/yml/companies.yml +1 -0
  265. data/vendor/activerecord/test/fixtures/naked/yml/courses.yml +1 -0
  266. data/vendor/activerecord/test/fixtures/owners.yml +7 -0
  267. data/vendor/activerecord/test/fixtures/parrots.yml +27 -0
  268. data/vendor/activerecord/test/fixtures/parrots_pirates.yml +7 -0
  269. data/vendor/activerecord/test/fixtures/people.yml +6 -0
  270. data/vendor/activerecord/test/fixtures/pets.yml +14 -0
  271. data/vendor/activerecord/test/fixtures/pirates.yml +9 -0
  272. data/vendor/activerecord/test/fixtures/posts.yml +49 -0
  273. data/vendor/activerecord/test/fixtures/price_estimates.yml +7 -0
  274. data/vendor/activerecord/test/fixtures/projects.yml +7 -0
  275. data/vendor/activerecord/test/fixtures/readers.yml +9 -0
  276. data/vendor/activerecord/test/fixtures/references.yml +17 -0
  277. data/vendor/activerecord/test/fixtures/reserved_words/distinct.yml +5 -0
  278. data/vendor/activerecord/test/fixtures/reserved_words/distincts_selects.yml +11 -0
  279. data/vendor/activerecord/test/fixtures/reserved_words/group.yml +14 -0
  280. data/vendor/activerecord/test/fixtures/reserved_words/select.yml +8 -0
  281. data/vendor/activerecord/test/fixtures/reserved_words/values.yml +7 -0
  282. data/vendor/activerecord/test/fixtures/ships.yml +5 -0
  283. data/vendor/activerecord/test/fixtures/sponsors.yml +9 -0
  284. data/vendor/activerecord/test/fixtures/subscribers.yml +7 -0
  285. data/vendor/activerecord/test/fixtures/subscriptions.yml +12 -0
  286. data/vendor/activerecord/test/fixtures/taggings.yml +28 -0
  287. data/vendor/activerecord/test/fixtures/tags.yml +7 -0
  288. data/vendor/activerecord/test/fixtures/tasks.yml +7 -0
  289. data/vendor/activerecord/test/fixtures/topics.yml +42 -0
  290. data/vendor/activerecord/test/fixtures/treasures.yml +10 -0
  291. data/vendor/activerecord/test/fixtures/vertices.yml +4 -0
  292. data/vendor/activerecord/test/fixtures/warehouse-things.yml +3 -0
  293. data/vendor/activerecord/test/migrations/decimal/1_give_me_big_numbers.rb +15 -0
  294. data/vendor/activerecord/test/migrations/duplicate/1_people_have_last_names.rb +9 -0
  295. data/vendor/activerecord/test/migrations/duplicate/2_we_need_reminders.rb +12 -0
  296. data/vendor/activerecord/test/migrations/duplicate/3_foo.rb +7 -0
  297. data/vendor/activerecord/test/migrations/duplicate/3_innocent_jointable.rb +12 -0
  298. data/vendor/activerecord/test/migrations/duplicate_names/20080507052938_chunky.rb +7 -0
  299. data/vendor/activerecord/test/migrations/duplicate_names/20080507053028_chunky.rb +7 -0
  300. data/vendor/activerecord/test/migrations/interleaved/pass_1/3_innocent_jointable.rb +12 -0
  301. data/vendor/activerecord/test/migrations/interleaved/pass_2/1_people_have_last_names.rb +9 -0
  302. data/vendor/activerecord/test/migrations/interleaved/pass_2/3_innocent_jointable.rb +12 -0
  303. data/vendor/activerecord/test/migrations/interleaved/pass_3/1_people_have_last_names.rb +9 -0
  304. data/vendor/activerecord/test/migrations/interleaved/pass_3/2_i_raise_on_down.rb +8 -0
  305. data/vendor/activerecord/test/migrations/interleaved/pass_3/3_innocent_jointable.rb +12 -0
  306. data/vendor/activerecord/test/migrations/missing/1000_people_have_middle_names.rb +9 -0
  307. data/vendor/activerecord/test/migrations/missing/1_people_have_last_names.rb +9 -0
  308. data/vendor/activerecord/test/migrations/missing/3_we_need_reminders.rb +12 -0
  309. data/vendor/activerecord/test/migrations/missing/4_innocent_jointable.rb +12 -0
  310. data/vendor/activerecord/test/migrations/valid/1_people_have_last_names.rb +9 -0
  311. data/vendor/activerecord/test/migrations/valid/2_we_need_reminders.rb +12 -0
  312. data/vendor/activerecord/test/migrations/valid/3_innocent_jointable.rb +12 -0
  313. data/vendor/activerecord/test/models/author.rb +137 -0
  314. data/vendor/activerecord/test/models/auto_id.rb +4 -0
  315. data/vendor/activerecord/test/models/binary.rb +2 -0
  316. data/vendor/activerecord/test/models/book.rb +4 -0
  317. data/vendor/activerecord/test/models/categorization.rb +5 -0
  318. data/vendor/activerecord/test/models/category.rb +30 -0
  319. data/vendor/activerecord/test/models/citation.rb +6 -0
  320. data/vendor/activerecord/test/models/club.rb +7 -0
  321. data/vendor/activerecord/test/models/column_name.rb +3 -0
  322. data/vendor/activerecord/test/models/comment.rb +25 -0
  323. data/vendor/activerecord/test/models/company.rb +132 -0
  324. data/vendor/activerecord/test/models/company_in_module.rb +61 -0
  325. data/vendor/activerecord/test/models/computer.rb +3 -0
  326. data/vendor/activerecord/test/models/contact.rb +16 -0
  327. data/vendor/activerecord/test/models/course.rb +3 -0
  328. data/vendor/activerecord/test/models/customer.rb +55 -0
  329. data/vendor/activerecord/test/models/default.rb +2 -0
  330. data/vendor/activerecord/test/models/developer.rb +79 -0
  331. data/vendor/activerecord/test/models/edge.rb +5 -0
  332. data/vendor/activerecord/test/models/entrant.rb +3 -0
  333. data/vendor/activerecord/test/models/guid.rb +2 -0
  334. data/vendor/activerecord/test/models/item.rb +7 -0
  335. data/vendor/activerecord/test/models/job.rb +5 -0
  336. data/vendor/activerecord/test/models/joke.rb +3 -0
  337. data/vendor/activerecord/test/models/keyboard.rb +3 -0
  338. data/vendor/activerecord/test/models/legacy_thing.rb +3 -0
  339. data/vendor/activerecord/test/models/matey.rb +4 -0
  340. data/vendor/activerecord/test/models/member.rb +9 -0
  341. data/vendor/activerecord/test/models/membership.rb +9 -0
  342. data/vendor/activerecord/test/models/minimalistic.rb +2 -0
  343. data/vendor/activerecord/test/models/mixed_case_monkey.rb +3 -0
  344. data/vendor/activerecord/test/models/movie.rb +5 -0
  345. data/vendor/activerecord/test/models/order.rb +4 -0
  346. data/vendor/activerecord/test/models/owner.rb +4 -0
  347. data/vendor/activerecord/test/models/parrot.rb +13 -0
  348. data/vendor/activerecord/test/models/person.rb +10 -0
  349. data/vendor/activerecord/test/models/pet.rb +4 -0
  350. data/vendor/activerecord/test/models/pirate.rb +9 -0
  351. data/vendor/activerecord/test/models/post.rb +85 -0
  352. data/vendor/activerecord/test/models/price_estimate.rb +3 -0
  353. data/vendor/activerecord/test/models/project.rb +29 -0
  354. data/vendor/activerecord/test/models/reader.rb +4 -0
  355. data/vendor/activerecord/test/models/reference.rb +4 -0
  356. data/vendor/activerecord/test/models/reply.rb +39 -0
  357. data/vendor/activerecord/test/models/ship.rb +3 -0
  358. data/vendor/activerecord/test/models/sponsor.rb +4 -0
  359. data/vendor/activerecord/test/models/subject.rb +4 -0
  360. data/vendor/activerecord/test/models/subscriber.rb +8 -0
  361. data/vendor/activerecord/test/models/subscription.rb +4 -0
  362. data/vendor/activerecord/test/models/tag.rb +7 -0
  363. data/vendor/activerecord/test/models/tagging.rb +10 -0
  364. data/vendor/activerecord/test/models/task.rb +3 -0
  365. data/vendor/activerecord/test/models/topic.rb +66 -0
  366. data/vendor/activerecord/test/models/treasure.rb +6 -0
  367. data/vendor/activerecord/test/models/vertex.rb +9 -0
  368. data/vendor/activerecord/test/models/warehouse_thing.rb +5 -0
  369. data/vendor/activerecord/test/schema/mysql_specific_schema.rb +12 -0
  370. data/vendor/activerecord/test/schema/postgresql_specific_schema.rb +103 -0
  371. data/vendor/activerecord/test/schema/schema.rb +429 -0
  372. data/vendor/activerecord/test/schema/schema2.rb +6 -0
  373. data/vendor/activerecord/test/schema/sqlite_specific_schema.rb +25 -0
  374. data/vendor/activerecord/test/schema/sqlserver_specific_schema.rb +5 -0
  375. data/vendor/activesupport/CHANGELOG +1193 -0
  376. data/vendor/activesupport/README +43 -0
  377. data/vendor/activesupport/lib/active_support/base64.rb +22 -0
  378. data/vendor/activesupport/lib/active_support/basic_object.rb +24 -0
  379. data/vendor/activesupport/lib/active_support/buffered_logger.rb +121 -0
  380. data/vendor/activesupport/lib/active_support/cache/compressed_mem_cache_store.rb +15 -0
  381. data/vendor/activesupport/lib/active_support/cache/drb_store.rb +15 -0
  382. data/vendor/activesupport/lib/active_support/cache/file_store.rb +70 -0
  383. data/vendor/activesupport/lib/active_support/cache/mem_cache_store.rb +100 -0
  384. data/vendor/activesupport/lib/active_support/cache/memory_store.rb +38 -0
  385. data/vendor/activesupport/lib/active_support/cache.rb +147 -0
  386. data/vendor/activesupport/lib/active_support/callbacks.rb +275 -0
  387. data/vendor/activesupport/lib/active_support/clean_logger.rb +127 -0
  388. data/vendor/activesupport/lib/active_support/core_ext/array/access.rb +26 -0
  389. data/vendor/activesupport/lib/active_support/core_ext/array/conversions.rb +178 -0
  390. data/vendor/activesupport/lib/active_support/core_ext/array/extract_options.rb +20 -0
  391. data/vendor/activesupport/lib/active_support/core_ext/array/grouping.rb +63 -0
  392. data/vendor/activesupport/lib/active_support/core_ext/array/random_access.rb +12 -0
  393. data/vendor/activesupport/lib/active_support/core_ext/array.rb +13 -0
  394. data/vendor/activesupport/lib/active_support/core_ext/base64/encoding.rb +13 -0
  395. data/vendor/activesupport/lib/active_support/core_ext/base64.rb +4 -0
  396. data/vendor/activesupport/lib/active_support/core_ext/benchmark.rb +12 -0
  397. data/vendor/activesupport/lib/active_support/core_ext/bigdecimal/conversions.rb +41 -0
  398. data/vendor/activesupport/lib/active_support/core_ext/bigdecimal.rb +6 -0
  399. data/vendor/activesupport/lib/active_support/core_ext/blank.rb +53 -0
  400. data/vendor/activesupport/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb +14 -0
  401. data/vendor/activesupport/lib/active_support/core_ext/cgi.rb +5 -0
  402. data/vendor/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb +54 -0
  403. data/vendor/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb +46 -0
  404. data/vendor/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb +140 -0
  405. data/vendor/activesupport/lib/active_support/core_ext/class/removal.rb +50 -0
  406. data/vendor/activesupport/lib/active_support/core_ext/class.rb +4 -0
  407. data/vendor/activesupport/lib/active_support/core_ext/date/behavior.rb +39 -0
  408. data/vendor/activesupport/lib/active_support/core_ext/date/calculations.rb +215 -0
  409. data/vendor/activesupport/lib/active_support/core_ext/date/conversions.rb +107 -0
  410. data/vendor/activesupport/lib/active_support/core_ext/date.rb +10 -0
  411. data/vendor/activesupport/lib/active_support/core_ext/date_time/calculations.rb +112 -0
  412. data/vendor/activesupport/lib/active_support/core_ext/date_time/conversions.rb +96 -0
  413. data/vendor/activesupport/lib/active_support/core_ext/date_time.rb +12 -0
  414. data/vendor/activesupport/lib/active_support/core_ext/duplicable.rb +37 -0
  415. data/vendor/activesupport/lib/active_support/core_ext/enumerable.rb +69 -0
  416. data/vendor/activesupport/lib/active_support/core_ext/exception.rb +41 -0
  417. data/vendor/activesupport/lib/active_support/core_ext/file.rb +21 -0
  418. data/vendor/activesupport/lib/active_support/core_ext/float/rounding.rb +24 -0
  419. data/vendor/activesupport/lib/active_support/core_ext/float.rb +5 -0
  420. data/vendor/activesupport/lib/active_support/core_ext/hash/conversions.rb +259 -0
  421. data/vendor/activesupport/lib/active_support/core_ext/hash/diff.rb +19 -0
  422. data/vendor/activesupport/lib/active_support/core_ext/hash/except.rb +25 -0
  423. data/vendor/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb +137 -0
  424. data/vendor/activesupport/lib/active_support/core_ext/hash/keys.rb +52 -0
  425. data/vendor/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb +28 -0
  426. data/vendor/activesupport/lib/active_support/core_ext/hash/slice.rb +30 -0
  427. data/vendor/activesupport/lib/active_support/core_ext/hash.rb +13 -0
  428. data/vendor/activesupport/lib/active_support/core_ext/integer/even_odd.rb +29 -0
  429. data/vendor/activesupport/lib/active_support/core_ext/integer/inflections.rb +20 -0
  430. data/vendor/activesupport/lib/active_support/core_ext/integer.rb +7 -0
  431. data/vendor/activesupport/lib/active_support/core_ext/kernel/agnostics.rb +11 -0
  432. data/vendor/activesupport/lib/active_support/core_ext/kernel/daemonizing.rb +7 -0
  433. data/vendor/activesupport/lib/active_support/core_ext/kernel/debugger.rb +13 -0
  434. data/vendor/activesupport/lib/active_support/core_ext/kernel/reporting.rb +59 -0
  435. data/vendor/activesupport/lib/active_support/core_ext/kernel/requires.rb +24 -0
  436. data/vendor/activesupport/lib/active_support/core_ext/kernel.rb +5 -0
  437. data/vendor/activesupport/lib/active_support/core_ext/load_error.rb +38 -0
  438. data/vendor/activesupport/lib/active_support/core_ext/logger.rb +16 -0
  439. data/vendor/activesupport/lib/active_support/core_ext/module/aliasing.rb +70 -0
  440. data/vendor/activesupport/lib/active_support/core_ext/module/attr_accessor_with_default.rb +31 -0
  441. data/vendor/activesupport/lib/active_support/core_ext/module/attr_internal.rb +32 -0
  442. data/vendor/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb +58 -0
  443. data/vendor/activesupport/lib/active_support/core_ext/module/delegation.rb +64 -0
  444. data/vendor/activesupport/lib/active_support/core_ext/module/inclusion.rb +30 -0
  445. data/vendor/activesupport/lib/active_support/core_ext/module/introspection.rb +75 -0
  446. data/vendor/activesupport/lib/active_support/core_ext/module/loading.rb +23 -0
  447. data/vendor/activesupport/lib/active_support/core_ext/module/model_naming.rb +22 -0
  448. data/vendor/activesupport/lib/active_support/core_ext/module.rb +13 -0
  449. data/vendor/activesupport/lib/active_support/core_ext/name_error.rb +17 -0
  450. data/vendor/activesupport/lib/active_support/core_ext/numeric/bytes.rb +44 -0
  451. data/vendor/activesupport/lib/active_support/core_ext/numeric/conversions.rb +19 -0
  452. data/vendor/activesupport/lib/active_support/core_ext/numeric/time.rb +91 -0
  453. data/vendor/activesupport/lib/active_support/core_ext/numeric.rb +9 -0
  454. data/vendor/activesupport/lib/active_support/core_ext/object/conversions.rb +14 -0
  455. data/vendor/activesupport/lib/active_support/core_ext/object/extending.rb +59 -0
  456. data/vendor/activesupport/lib/active_support/core_ext/object/instance_variables.rb +74 -0
  457. data/vendor/activesupport/lib/active_support/core_ext/object/misc.rb +59 -0
  458. data/vendor/activesupport/lib/active_support/core_ext/object.rb +4 -0
  459. data/vendor/activesupport/lib/active_support/core_ext/pathname/clean_within.rb +14 -0
  460. data/vendor/activesupport/lib/active_support/core_ext/pathname.rb +7 -0
  461. data/vendor/activesupport/lib/active_support/core_ext/proc.rb +12 -0
  462. data/vendor/activesupport/lib/active_support/core_ext/process/daemon.rb +25 -0
  463. data/vendor/activesupport/lib/active_support/core_ext/process.rb +1 -0
  464. data/vendor/activesupport/lib/active_support/core_ext/range/blockless_step.rb +32 -0
  465. data/vendor/activesupport/lib/active_support/core_ext/range/conversions.rb +27 -0
  466. data/vendor/activesupport/lib/active_support/core_ext/range/include_range.rb +30 -0
  467. data/vendor/activesupport/lib/active_support/core_ext/range/overlaps.rb +15 -0
  468. data/vendor/activesupport/lib/active_support/core_ext/range.rb +11 -0
  469. data/vendor/activesupport/lib/active_support/core_ext/rexml.rb +35 -0
  470. data/vendor/activesupport/lib/active_support/core_ext/string/access.rb +82 -0
  471. data/vendor/activesupport/lib/active_support/core_ext/string/conversions.rb +28 -0
  472. data/vendor/activesupport/lib/active_support/core_ext/string/filters.rb +26 -0
  473. data/vendor/activesupport/lib/active_support/core_ext/string/inflections.rb +148 -0
  474. data/vendor/activesupport/lib/active_support/core_ext/string/iterators.rb +21 -0
  475. data/vendor/activesupport/lib/active_support/core_ext/string/starts_ends_with.rb +35 -0
  476. data/vendor/activesupport/lib/active_support/core_ext/string/unicode.rb +66 -0
  477. data/vendor/activesupport/lib/active_support/core_ext/string/xchar.rb +11 -0
  478. data/vendor/activesupport/lib/active_support/core_ext/string.rb +18 -0
  479. data/vendor/activesupport/lib/active_support/core_ext/symbol.rb +14 -0
  480. data/vendor/activesupport/lib/active_support/core_ext/test/unit/assertions.rb +64 -0
  481. data/vendor/activesupport/lib/active_support/core_ext/test.rb +1 -0
  482. data/vendor/activesupport/lib/active_support/core_ext/time/behavior.rb +13 -0
  483. data/vendor/activesupport/lib/active_support/core_ext/time/calculations.rb +276 -0
  484. data/vendor/activesupport/lib/active_support/core_ext/time/conversions.rb +89 -0
  485. data/vendor/activesupport/lib/active_support/core_ext/time/zones.rb +86 -0
  486. data/vendor/activesupport/lib/active_support/core_ext/time.rb +42 -0
  487. data/vendor/activesupport/lib/active_support/core_ext.rb +4 -0
  488. data/vendor/activesupport/lib/active_support/dependencies.rb +553 -0
  489. data/vendor/activesupport/lib/active_support/deprecation.rb +223 -0
  490. data/vendor/activesupport/lib/active_support/duration.rb +96 -0
  491. data/vendor/activesupport/lib/active_support/gzip.rb +25 -0
  492. data/vendor/activesupport/lib/active_support/inflections.rb +55 -0
  493. data/vendor/activesupport/lib/active_support/inflector.rb +313 -0
  494. data/vendor/activesupport/lib/active_support/json/decoding.rb +63 -0
  495. data/vendor/activesupport/lib/active_support/json/encoders/date.rb +14 -0
  496. data/vendor/activesupport/lib/active_support/json/encoders/date_time.rb +14 -0
  497. data/vendor/activesupport/lib/active_support/json/encoders/enumerable.rb +12 -0
  498. data/vendor/activesupport/lib/active_support/json/encoders/false_class.rb +5 -0
  499. data/vendor/activesupport/lib/active_support/json/encoders/hash.rb +47 -0
  500. data/vendor/activesupport/lib/active_support/json/encoders/nil_class.rb +5 -0
  501. data/vendor/activesupport/lib/active_support/json/encoders/numeric.rb +5 -0
  502. data/vendor/activesupport/lib/active_support/json/encoders/object.rb +6 -0
  503. data/vendor/activesupport/lib/active_support/json/encoders/regexp.rb +5 -0
  504. data/vendor/activesupport/lib/active_support/json/encoders/string.rb +36 -0
  505. data/vendor/activesupport/lib/active_support/json/encoders/symbol.rb +5 -0
  506. data/vendor/activesupport/lib/active_support/json/encoders/time.rb +14 -0
  507. data/vendor/activesupport/lib/active_support/json/encoders/true_class.rb +5 -0
  508. data/vendor/activesupport/lib/active_support/json/encoding.rb +37 -0
  509. data/vendor/activesupport/lib/active_support/json/variable.rb +10 -0
  510. data/vendor/activesupport/lib/active_support/json.rb +23 -0
  511. data/vendor/activesupport/lib/active_support/multibyte/chars.rb +137 -0
  512. data/vendor/activesupport/lib/active_support/multibyte/generators/generate_tables.rb +149 -0
  513. data/vendor/activesupport/lib/active_support/multibyte/handlers/passthru_handler.rb +9 -0
  514. data/vendor/activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb +564 -0
  515. data/vendor/activesupport/lib/active_support/multibyte/handlers/utf8_handler_proc.rb +43 -0
  516. data/vendor/activesupport/lib/active_support/multibyte.rb +9 -0
  517. data/vendor/activesupport/lib/active_support/option_merger.rb +25 -0
  518. data/vendor/activesupport/lib/active_support/ordered_hash.rb +43 -0
  519. data/vendor/activesupport/lib/active_support/ordered_options.rb +19 -0
  520. data/vendor/activesupport/lib/active_support/string_inquirer.rb +11 -0
  521. data/vendor/activesupport/lib/active_support/test_case.rb +13 -0
  522. data/vendor/activesupport/lib/active_support/testing/default.rb +9 -0
  523. data/vendor/activesupport/lib/active_support/testing/setup_and_teardown.rb +93 -0
  524. data/vendor/activesupport/lib/active_support/time_with_zone.rb +304 -0
  525. data/vendor/activesupport/lib/active_support/values/time_zone.rb +396 -0
  526. data/vendor/activesupport/lib/active_support/values/unicode_tables.dat +0 -0
  527. data/vendor/activesupport/lib/active_support/vendor/builder-2.1.2/blankslate.rb +113 -0
  528. data/vendor/activesupport/lib/active_support/vendor/builder-2.1.2/builder/blankslate.rb +20 -0
  529. data/vendor/activesupport/lib/active_support/vendor/builder-2.1.2/builder/css.rb +250 -0
  530. data/vendor/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xchar.rb +115 -0
  531. data/vendor/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlbase.rb +139 -0
  532. data/vendor/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb +63 -0
  533. data/vendor/activesupport/lib/active_support/vendor/builder-2.1.2/builder/xmlmarkup.rb +328 -0
  534. data/vendor/activesupport/lib/active_support/vendor/builder-2.1.2/builder.rb +13 -0
  535. data/vendor/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb +849 -0
  536. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/data_timezone.rb +47 -0
  537. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/data_timezone_info.rb +228 -0
  538. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Algiers.rb +55 -0
  539. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Cairo.rb +219 -0
  540. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Casablanca.rb +40 -0
  541. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Harare.rb +18 -0
  542. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Johannesburg.rb +25 -0
  543. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Monrovia.rb +22 -0
  544. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Africa/Nairobi.rb +23 -0
  545. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Argentina/Buenos_Aires.rb +166 -0
  546. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Argentina/San_Juan.rb +170 -0
  547. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Bogota.rb +23 -0
  548. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Caracas.rb +23 -0
  549. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Chicago.rb +283 -0
  550. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Chihuahua.rb +136 -0
  551. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Denver.rb +204 -0
  552. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Godthab.rb +161 -0
  553. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Guatemala.rb +27 -0
  554. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Halifax.rb +274 -0
  555. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Indiana/Indianapolis.rb +149 -0
  556. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Juneau.rb +194 -0
  557. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/La_Paz.rb +22 -0
  558. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Lima.rb +35 -0
  559. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Los_Angeles.rb +232 -0
  560. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Mazatlan.rb +139 -0
  561. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Mexico_City.rb +144 -0
  562. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Monterrey.rb +131 -0
  563. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/New_York.rb +282 -0
  564. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Phoenix.rb +30 -0
  565. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Regina.rb +74 -0
  566. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Santiago.rb +205 -0
  567. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/St_Johns.rb +288 -0
  568. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/America/Tijuana.rb +196 -0
  569. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Almaty.rb +67 -0
  570. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Baghdad.rb +73 -0
  571. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Baku.rb +161 -0
  572. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Bangkok.rb +20 -0
  573. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Chongqing.rb +33 -0
  574. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Dhaka.rb +27 -0
  575. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Hong_Kong.rb +87 -0
  576. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Irkutsk.rb +165 -0
  577. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Jakarta.rb +30 -0
  578. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Jerusalem.rb +163 -0
  579. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kabul.rb +20 -0
  580. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kamchatka.rb +163 -0
  581. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Karachi.rb +30 -0
  582. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Katmandu.rb +20 -0
  583. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kolkata.rb +25 -0
  584. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Krasnoyarsk.rb +163 -0
  585. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kuala_Lumpur.rb +31 -0
  586. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Kuwait.rb +18 -0
  587. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Magadan.rb +163 -0
  588. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Muscat.rb +18 -0
  589. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Novosibirsk.rb +164 -0
  590. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Rangoon.rb +24 -0
  591. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Riyadh.rb +18 -0
  592. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Seoul.rb +34 -0
  593. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Shanghai.rb +35 -0
  594. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Singapore.rb +33 -0
  595. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Taipei.rb +59 -0
  596. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Tashkent.rb +47 -0
  597. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Tbilisi.rb +78 -0
  598. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Tehran.rb +121 -0
  599. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Tokyo.rb +30 -0
  600. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Ulaanbaatar.rb +65 -0
  601. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Urumqi.rb +33 -0
  602. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Vladivostok.rb +164 -0
  603. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Yakutsk.rb +163 -0
  604. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Yekaterinburg.rb +165 -0
  605. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Asia/Yerevan.rb +165 -0
  606. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Atlantic/Azores.rb +270 -0
  607. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Atlantic/Cape_Verde.rb +23 -0
  608. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Atlantic/South_Georgia.rb +18 -0
  609. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Adelaide.rb +187 -0
  610. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Brisbane.rb +35 -0
  611. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Darwin.rb +29 -0
  612. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Hobart.rb +193 -0
  613. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Melbourne.rb +185 -0
  614. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Perth.rb +37 -0
  615. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Australia/Sydney.rb +185 -0
  616. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Etc/UTC.rb +16 -0
  617. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Amsterdam.rb +228 -0
  618. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Athens.rb +185 -0
  619. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Belgrade.rb +163 -0
  620. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Berlin.rb +188 -0
  621. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Bratislava.rb +13 -0
  622. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Brussels.rb +232 -0
  623. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Bucharest.rb +181 -0
  624. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Budapest.rb +197 -0
  625. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Copenhagen.rb +179 -0
  626. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Dublin.rb +276 -0
  627. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Helsinki.rb +163 -0
  628. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Istanbul.rb +218 -0
  629. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Kiev.rb +168 -0
  630. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Lisbon.rb +268 -0
  631. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Ljubljana.rb +13 -0
  632. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/London.rb +288 -0
  633. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Madrid.rb +211 -0
  634. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Minsk.rb +170 -0
  635. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Moscow.rb +181 -0
  636. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Paris.rb +232 -0
  637. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Prague.rb +187 -0
  638. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Riga.rb +176 -0
  639. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Rome.rb +215 -0
  640. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Sarajevo.rb +13 -0
  641. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Skopje.rb +13 -0
  642. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Sofia.rb +173 -0
  643. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Stockholm.rb +165 -0
  644. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Tallinn.rb +172 -0
  645. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Vienna.rb +183 -0
  646. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Vilnius.rb +170 -0
  647. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Warsaw.rb +212 -0
  648. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Europe/Zagreb.rb +13 -0
  649. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Auckland.rb +202 -0
  650. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Fiji.rb +23 -0
  651. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Guam.rb +22 -0
  652. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Honolulu.rb +28 -0
  653. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Majuro.rb +20 -0
  654. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Midway.rb +25 -0
  655. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Noumea.rb +25 -0
  656. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Pago_Pago.rb +26 -0
  657. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Port_Moresby.rb +20 -0
  658. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/definitions/Pacific/Tongatapu.rb +27 -0
  659. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/info_timezone.rb +52 -0
  660. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/linked_timezone.rb +51 -0
  661. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/linked_timezone_info.rb +44 -0
  662. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/offset_rationals.rb +95 -0
  663. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/time_or_datetime.rb +292 -0
  664. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone.rb +508 -0
  665. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_definition.rb +56 -0
  666. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_info.rb +40 -0
  667. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_offset_info.rb +94 -0
  668. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_period.rb +198 -0
  669. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo/timezone_transition_info.rb +138 -0
  670. data/vendor/activesupport/lib/active_support/vendor/tzinfo-0.3.9/tzinfo.rb +33 -0
  671. data/vendor/activesupport/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb +1021 -0
  672. data/vendor/activesupport/lib/active_support/vendor.rb +26 -0
  673. data/vendor/activesupport/lib/active_support/version.rb +9 -0
  674. data/vendor/activesupport/lib/active_support/whiny_nil.rb +58 -0
  675. data/vendor/activesupport/lib/active_support.rb +61 -0
  676. data/vendor/activesupport/lib/activesupport.rb +1 -0
  677. data/vendor/isaac/LICENSE +26 -0
  678. data/vendor/isaac/README +78 -0
  679. data/vendor/isaac/TODO +3 -0
  680. data/vendor/isaac/VERSIONS +3 -0
  681. data/vendor/isaac/crypt/ISAAC.rb +171 -0
  682. data/vendor/isaac/isaac.gemspec +39 -0
  683. data/vendor/isaac/setup.rb +596 -0
  684. data/vendor/isaac/test/TC_ISAAC.rb +76 -0
  685. data/vendor/json/CHANGES +93 -0
  686. data/vendor/json/GPL +340 -0
  687. data/vendor/json/README +78 -0
  688. data/vendor/json/RUBY +58 -0
  689. data/vendor/json/Rakefile +309 -0
  690. data/vendor/json/TODO +1 -0
  691. data/vendor/json/VERSION +1 -0
  692. data/vendor/json/benchmarks/benchmark.txt +133 -0
  693. data/vendor/json/benchmarks/benchmark_generator.rb +48 -0
  694. data/vendor/json/benchmarks/benchmark_parser.rb +26 -0
  695. data/vendor/json/benchmarks/benchmark_rails.rb +26 -0
  696. data/vendor/json/bin/edit_json.rb +10 -0
  697. data/vendor/json/bin/prettify_json.rb +76 -0
  698. data/vendor/json/data/example.json +1 -0
  699. data/vendor/json/data/index.html +38 -0
  700. data/vendor/json/data/prototype.js +4184 -0
  701. data/vendor/json/ext/json/ext/generator/extconf.rb +9 -0
  702. data/vendor/json/ext/json/ext/generator/generator.c +875 -0
  703. data/vendor/json/ext/json/ext/generator/unicode.c +182 -0
  704. data/vendor/json/ext/json/ext/generator/unicode.h +53 -0
  705. data/vendor/json/ext/json/ext/parser/extconf.rb +9 -0
  706. data/vendor/json/ext/json/ext/parser/parser.c +1758 -0
  707. data/vendor/json/ext/json/ext/parser/parser.rl +638 -0
  708. data/vendor/json/ext/json/ext/parser/unicode.c +154 -0
  709. data/vendor/json/ext/json/ext/parser/unicode.h +58 -0
  710. data/vendor/json/install.rb +26 -0
  711. data/vendor/json/lib/json/Array.xpm +21 -0
  712. data/vendor/json/lib/json/FalseClass.xpm +21 -0
  713. data/vendor/json/lib/json/Hash.xpm +21 -0
  714. data/vendor/json/lib/json/Key.xpm +73 -0
  715. data/vendor/json/lib/json/NilClass.xpm +21 -0
  716. data/vendor/json/lib/json/Numeric.xpm +28 -0
  717. data/vendor/json/lib/json/String.xpm +96 -0
  718. data/vendor/json/lib/json/TrueClass.xpm +21 -0
  719. data/vendor/json/lib/json/add/core.rb +135 -0
  720. data/vendor/json/lib/json/add/rails.rb +58 -0
  721. data/vendor/json/lib/json/common.rb +354 -0
  722. data/vendor/json/lib/json/editor.rb +1362 -0
  723. data/vendor/json/lib/json/ext.rb +13 -0
  724. data/vendor/json/lib/json/json.xpm +1499 -0
  725. data/vendor/json/lib/json/pure/generator.rb +394 -0
  726. data/vendor/json/lib/json/pure/parser.rb +259 -0
  727. data/vendor/json/lib/json/pure.rb +75 -0
  728. data/vendor/json/lib/json/version.rb +9 -0
  729. data/vendor/json/lib/json.rb +235 -0
  730. data/vendor/json/tests/fixtures/fail1.json +1 -0
  731. data/vendor/json/tests/fixtures/fail10.json +1 -0
  732. data/vendor/json/tests/fixtures/fail11.json +1 -0
  733. data/vendor/json/tests/fixtures/fail12.json +1 -0
  734. data/vendor/json/tests/fixtures/fail13.json +1 -0
  735. data/vendor/json/tests/fixtures/fail14.json +1 -0
  736. data/vendor/json/tests/fixtures/fail18.json +1 -0
  737. data/vendor/json/tests/fixtures/fail19.json +1 -0
  738. data/vendor/json/tests/fixtures/fail2.json +1 -0
  739. data/vendor/json/tests/fixtures/fail20.json +1 -0
  740. data/vendor/json/tests/fixtures/fail21.json +1 -0
  741. data/vendor/json/tests/fixtures/fail22.json +1 -0
  742. data/vendor/json/tests/fixtures/fail23.json +1 -0
  743. data/vendor/json/tests/fixtures/fail24.json +1 -0
  744. data/vendor/json/tests/fixtures/fail25.json +1 -0
  745. data/vendor/json/tests/fixtures/fail27.json +2 -0
  746. data/vendor/json/tests/fixtures/fail28.json +2 -0
  747. data/vendor/json/tests/fixtures/fail3.json +1 -0
  748. data/vendor/json/tests/fixtures/fail4.json +1 -0
  749. data/vendor/json/tests/fixtures/fail5.json +1 -0
  750. data/vendor/json/tests/fixtures/fail6.json +1 -0
  751. data/vendor/json/tests/fixtures/fail7.json +1 -0
  752. data/vendor/json/tests/fixtures/fail8.json +1 -0
  753. data/vendor/json/tests/fixtures/fail9.json +1 -0
  754. data/vendor/json/tests/fixtures/pass1.json +56 -0
  755. data/vendor/json/tests/fixtures/pass15.json +1 -0
  756. data/vendor/json/tests/fixtures/pass16.json +1 -0
  757. data/vendor/json/tests/fixtures/pass17.json +1 -0
  758. data/vendor/json/tests/fixtures/pass2.json +1 -0
  759. data/vendor/json/tests/fixtures/pass26.json +1 -0
  760. data/vendor/json/tests/fixtures/pass3.json +6 -0
  761. data/vendor/json/tests/runner.rb +25 -0
  762. data/vendor/json/tests/test_json.rb +293 -0
  763. data/vendor/json/tests/test_json_addition.rb +161 -0
  764. data/vendor/json/tests/test_json_fixtures.rb +30 -0
  765. data/vendor/json/tests/test_json_generate.rb +100 -0
  766. data/vendor/json/tests/test_json_rails.rb +118 -0
  767. data/vendor/json/tests/test_json_unicode.rb +61 -0
  768. data/vendor/json/tools/fuzz.rb +140 -0
  769. data/vendor/json/tools/server.rb +62 -0
  770. data/vendor/rack/AUTHORS +8 -0
  771. data/vendor/rack/COPYING +18 -0
  772. data/vendor/rack/KNOWN-ISSUES +18 -0
  773. data/vendor/rack/RDOX +265 -0
  774. data/vendor/rack/README +287 -0
  775. data/vendor/rack/Rakefile +179 -0
  776. data/vendor/rack/SPEC +126 -0
  777. data/vendor/rack/bin/rackup +172 -0
  778. data/vendor/rack/contrib/rack_logo.svg +111 -0
  779. data/vendor/rack/example/lobster.ru +4 -0
  780. data/vendor/rack/example/protectedlobster.rb +14 -0
  781. data/vendor/rack/example/protectedlobster.ru +8 -0
  782. data/vendor/rack/lib/rack/adapter/camping.rb +22 -0
  783. data/vendor/rack/lib/rack/auth/abstract/handler.rb +28 -0
  784. data/vendor/rack/lib/rack/auth/abstract/request.rb +37 -0
  785. data/vendor/rack/lib/rack/auth/basic.rb +58 -0
  786. data/vendor/rack/lib/rack/auth/digest/md5.rb +124 -0
  787. data/vendor/rack/lib/rack/auth/digest/nonce.rb +51 -0
  788. data/vendor/rack/lib/rack/auth/digest/params.rb +55 -0
  789. data/vendor/rack/lib/rack/auth/digest/request.rb +40 -0
  790. data/vendor/rack/lib/rack/auth/openid.rb +437 -0
  791. data/vendor/rack/lib/rack/builder.rb +56 -0
  792. data/vendor/rack/lib/rack/cascade.rb +36 -0
  793. data/vendor/rack/lib/rack/commonlogger.rb +61 -0
  794. data/vendor/rack/lib/rack/deflater.rb +63 -0
  795. data/vendor/rack/lib/rack/directory.rb +158 -0
  796. data/vendor/rack/lib/rack/file.rb +116 -0
  797. data/vendor/rack/lib/rack/handler/cgi.rb +57 -0
  798. data/vendor/rack/lib/rack/handler/evented_mongrel.rb +8 -0
  799. data/vendor/rack/lib/rack/handler/fastcgi.rb +84 -0
  800. data/vendor/rack/lib/rack/handler/lsws.rb +52 -0
  801. data/vendor/rack/lib/rack/handler/mongrel.rb +78 -0
  802. data/vendor/rack/lib/rack/handler/scgi.rb +57 -0
  803. data/vendor/rack/lib/rack/handler/webrick.rb +57 -0
  804. data/vendor/rack/lib/rack/handler.rb +44 -0
  805. data/vendor/rack/lib/rack/lint.rb +401 -0
  806. data/vendor/rack/lib/rack/lobster.rb +65 -0
  807. data/vendor/rack/lib/rack/mock.rb +160 -0
  808. data/vendor/rack/lib/rack/recursive.rb +57 -0
  809. data/vendor/rack/lib/rack/reloader.rb +64 -0
  810. data/vendor/rack/lib/rack/request.rb +209 -0
  811. data/vendor/rack/lib/rack/response.rb +166 -0
  812. data/vendor/rack/lib/rack/session/abstract/id.rb +140 -0
  813. data/vendor/rack/lib/rack/session/cookie.rb +71 -0
  814. data/vendor/rack/lib/rack/session/memcache.rb +97 -0
  815. data/vendor/rack/lib/rack/session/pool.rb +73 -0
  816. data/vendor/rack/lib/rack/showexceptions.rb +344 -0
  817. data/vendor/rack/lib/rack/showstatus.rb +105 -0
  818. data/vendor/rack/lib/rack/static.rb +38 -0
  819. data/vendor/rack/lib/rack/urlmap.rb +48 -0
  820. data/vendor/rack/lib/rack/utils.rb +318 -0
  821. data/vendor/rack/lib/rack.rb +81 -0
  822. data/vendor/rack/test/cgi/lighttpd.conf +20 -0
  823. data/vendor/rack/test/cgi/test +9 -0
  824. data/vendor/rack/test/cgi/test.fcgi +8 -0
  825. data/vendor/rack/test/cgi/test.ru +7 -0
  826. data/vendor/rack/test/spec_rack_auth_basic.rb +69 -0
  827. data/vendor/rack/test/spec_rack_auth_digest.rb +169 -0
  828. data/vendor/rack/test/spec_rack_auth_openid.rb +137 -0
  829. data/vendor/rack/test/spec_rack_builder.rb +50 -0
  830. data/vendor/rack/test/spec_rack_camping.rb +51 -0
  831. data/vendor/rack/test/spec_rack_cascade.rb +50 -0
  832. data/vendor/rack/test/spec_rack_cgi.rb +89 -0
  833. data/vendor/rack/test/spec_rack_commonlogger.rb +32 -0
  834. data/vendor/rack/test/spec_rack_deflater.rb +70 -0
  835. data/vendor/rack/test/spec_rack_directory.rb +56 -0
  836. data/vendor/rack/test/spec_rack_fastcgi.rb +89 -0
  837. data/vendor/rack/test/spec_rack_file.rb +50 -0
  838. data/vendor/rack/test/spec_rack_handler.rb +24 -0
  839. data/vendor/rack/test/spec_rack_lint.rb +303 -0
  840. data/vendor/rack/test/spec_rack_lobster.rb +45 -0
  841. data/vendor/rack/test/spec_rack_mock.rb +152 -0
  842. data/vendor/rack/test/spec_rack_mongrel.rb +170 -0
  843. data/vendor/rack/test/spec_rack_recursive.rb +77 -0
  844. data/vendor/rack/test/spec_rack_request.rb +401 -0
  845. data/vendor/rack/test/spec_rack_response.rb +167 -0
  846. data/vendor/rack/test/spec_rack_session_cookie.rb +49 -0
  847. data/vendor/rack/test/spec_rack_session_memcache.rb +132 -0
  848. data/vendor/rack/test/spec_rack_session_pool.rb +84 -0
  849. data/vendor/rack/test/spec_rack_showexceptions.rb +21 -0
  850. data/vendor/rack/test/spec_rack_showstatus.rb +72 -0
  851. data/vendor/rack/test/spec_rack_static.rb +37 -0
  852. data/vendor/rack/test/spec_rack_urlmap.rb +175 -0
  853. data/vendor/rack/test/spec_rack_utils.rb +174 -0
  854. data/vendor/rack/test/spec_rack_webrick.rb +106 -0
  855. data/vendor/rack/test/testrequest.rb +45 -0
  856. data/vendor/sinatra/CHANGELOG +64 -0
  857. data/vendor/sinatra/LICENSE +22 -0
  858. data/vendor/sinatra/README.rdoc +533 -0
  859. data/vendor/sinatra/Rakefile +111 -0
  860. data/vendor/sinatra/images/404.png +0 -0
  861. data/vendor/sinatra/images/500.png +0 -0
  862. data/vendor/sinatra/lib/sinatra/rack/handler/mongrel.rb +85 -0
  863. data/vendor/sinatra/lib/sinatra/test/methods.rb +76 -0
  864. data/vendor/sinatra/lib/sinatra/test/rspec.rb +10 -0
  865. data/vendor/sinatra/lib/sinatra/test/spec.rb +10 -0
  866. data/vendor/sinatra/lib/sinatra/test/unit.rb +13 -0
  867. data/vendor/sinatra/lib/sinatra.rb +1477 -0
  868. data/vendor/sinatra/sinatra.gemspec +78 -0
  869. data/vendor/sinatra/test/app_test.rb +299 -0
  870. data/vendor/sinatra/test/application_test.rb +318 -0
  871. data/vendor/sinatra/test/builder_test.rb +101 -0
  872. data/vendor/sinatra/test/custom_error_test.rb +62 -0
  873. data/vendor/sinatra/test/erb_test.rb +136 -0
  874. data/vendor/sinatra/test/event_context_test.rb +15 -0
  875. data/vendor/sinatra/test/events_test.rb +47 -0
  876. data/vendor/sinatra/test/filter_test.rb +30 -0
  877. data/vendor/sinatra/test/haml_test.rb +233 -0
  878. data/vendor/sinatra/test/helper.rb +7 -0
  879. data/vendor/sinatra/test/mapped_error_test.rb +72 -0
  880. data/vendor/sinatra/test/pipeline_test.rb +66 -0
  881. data/vendor/sinatra/test/public/foo.xml +1 -0
  882. data/vendor/sinatra/test/sass_test.rb +57 -0
  883. data/vendor/sinatra/test/sessions_test.rb +39 -0
  884. data/vendor/sinatra/test/streaming_test.rb +118 -0
  885. data/vendor/sinatra/test/sym_params_test.rb +19 -0
  886. data/vendor/sinatra/test/template_test.rb +30 -0
  887. data/vendor/sinatra/test/use_in_file_templates_test.rb +47 -0
  888. data/vendor/sinatra/test/views/foo.builder +1 -0
  889. data/vendor/sinatra/test/views/foo.erb +1 -0
  890. data/vendor/sinatra/test/views/foo.haml +1 -0
  891. data/vendor/sinatra/test/views/foo.sass +2 -0
  892. data/vendor/sinatra/test/views/foo_layout.erb +2 -0
  893. data/vendor/sinatra/test/views/foo_layout.haml +2 -0
  894. data/vendor/sinatra/test/views/layout_test/foo.builder +1 -0
  895. data/vendor/sinatra/test/views/layout_test/foo.erb +1 -0
  896. data/vendor/sinatra/test/views/layout_test/foo.haml +1 -0
  897. data/vendor/sinatra/test/views/layout_test/foo.sass +2 -0
  898. data/vendor/sinatra/test/views/layout_test/layout.builder +3 -0
  899. data/vendor/sinatra/test/views/layout_test/layout.erb +1 -0
  900. data/vendor/sinatra/test/views/layout_test/layout.haml +1 -0
  901. data/vendor/sinatra/test/views/layout_test/layout.sass +2 -0
  902. data/vendor/sinatra/test/views/no_layout/no_layout.builder +1 -0
  903. data/vendor/sinatra/test/views/no_layout/no_layout.haml +1 -0
  904. metadata +1121 -0
@@ -0,0 +1,2012 @@
1
+ require 'active_record/associations/association_proxy'
2
+ require 'active_record/associations/association_collection'
3
+ require 'active_record/associations/belongs_to_association'
4
+ require 'active_record/associations/belongs_to_polymorphic_association'
5
+ require 'active_record/associations/has_one_association'
6
+ require 'active_record/associations/has_many_association'
7
+ require 'active_record/associations/has_many_through_association'
8
+ require 'active_record/associations/has_and_belongs_to_many_association'
9
+ require 'active_record/associations/has_one_through_association'
10
+
11
+ module ActiveRecord
12
+ class HasManyThroughAssociationNotFoundError < ActiveRecordError #:nodoc:
13
+ def initialize(owner_class_name, reflection)
14
+ super("Could not find the association #{reflection.options[:through].inspect} in model #{owner_class_name}")
15
+ end
16
+ end
17
+
18
+ class HasManyThroughAssociationPolymorphicError < ActiveRecordError #:nodoc:
19
+ def initialize(owner_class_name, reflection, source_reflection)
20
+ super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' on the polymorphic object '#{source_reflection.class_name}##{source_reflection.name}'.")
21
+ end
22
+ end
23
+
24
+ class HasManyThroughAssociationPointlessSourceTypeError < ActiveRecordError #:nodoc:
25
+ def initialize(owner_class_name, reflection, source_reflection)
26
+ super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' with a :source_type option if the '#{reflection.through_reflection.class_name}##{source_reflection.name}' is not polymorphic. Try removing :source_type on your association.")
27
+ end
28
+ end
29
+
30
+ class HasManyThroughSourceAssociationNotFoundError < ActiveRecordError #:nodoc:
31
+ def initialize(reflection)
32
+ through_reflection = reflection.through_reflection
33
+ source_reflection_names = reflection.source_reflection_names
34
+ source_associations = reflection.through_reflection.klass.reflect_on_all_associations.collect { |a| a.name.inspect }
35
+ super("Could not find the source association(s) #{source_reflection_names.collect(&:inspect).to_sentence :connector => 'or'} in model #{through_reflection.klass}. Try 'has_many #{reflection.name.inspect}, :through => #{through_reflection.name.inspect}, :source => <name>'. Is it one of #{source_associations.to_sentence :connector => 'or'}?")
36
+ end
37
+ end
38
+
39
+ class HasManyThroughSourceAssociationMacroError < ActiveRecordError #:nodoc:
40
+ def initialize(reflection)
41
+ through_reflection = reflection.through_reflection
42
+ source_reflection = reflection.source_reflection
43
+ super("Invalid source reflection macro :#{source_reflection.macro}#{" :through" if source_reflection.options[:through]} for has_many #{reflection.name.inspect}, :through => #{through_reflection.name.inspect}. Use :source to specify the source reflection.")
44
+ end
45
+ end
46
+
47
+ class HasManyThroughCantAssociateThroughHasManyReflection < ActiveRecordError #:nodoc:
48
+ def initialize(owner, reflection)
49
+ super("Cannot modify association '#{owner.class.name}##{reflection.name}' because the source reflection class '#{reflection.source_reflection.class_name}' is associated to '#{reflection.through_reflection.class_name}' via :#{reflection.source_reflection.macro}.")
50
+ end
51
+ end
52
+ class HasManyThroughCantAssociateNewRecords < ActiveRecordError #:nodoc:
53
+ def initialize(owner, reflection)
54
+ super("Cannot associate new records through '#{owner.class.name}##{reflection.name}' on '#{reflection.source_reflection.class_name rescue nil}##{reflection.source_reflection.name rescue nil}'. Both records must have an id in order to create the has_many :through record associating them.")
55
+ end
56
+ end
57
+
58
+ class HasManyThroughCantDissociateNewRecords < ActiveRecordError #:nodoc:
59
+ def initialize(owner, reflection)
60
+ super("Cannot dissociate new records through '#{owner.class.name}##{reflection.name}' on '#{reflection.source_reflection.class_name rescue nil}##{reflection.source_reflection.name rescue nil}'. Both records must have an id in order to delete the has_many :through record associating them.")
61
+ end
62
+ end
63
+
64
+ class EagerLoadPolymorphicError < ActiveRecordError #:nodoc:
65
+ def initialize(reflection)
66
+ super("Can not eagerly load the polymorphic association #{reflection.name.inspect}")
67
+ end
68
+ end
69
+
70
+ class ReadOnlyAssociation < ActiveRecordError #:nodoc:
71
+ def initialize(reflection)
72
+ super("Can not add to a has_many :through association. Try adding to #{reflection.through_reflection.name.inspect}.")
73
+ end
74
+ end
75
+
76
+ module Associations # :nodoc:
77
+ def self.included(base)
78
+ base.extend(ClassMethods)
79
+ end
80
+
81
+ # Clears out the association cache
82
+ def clear_association_cache #:nodoc:
83
+ self.class.reflect_on_all_associations.to_a.each do |assoc|
84
+ instance_variable_set "@#{assoc.name}", nil
85
+ end unless self.new_record?
86
+ end
87
+
88
+ # Associations are a set of macro-like class methods for tying objects together through foreign keys. They express relationships like
89
+ # "Project has one Project Manager" or "Project belongs to a Portfolio". Each macro adds a number of methods to the class which are
90
+ # specialized according to the collection or association symbol and the options hash. It works much the same way as Ruby's own <tt>attr*</tt>
91
+ # methods. Example:
92
+ #
93
+ # class Project < ActiveRecord::Base
94
+ # belongs_to :portfolio
95
+ # has_one :project_manager
96
+ # has_many :milestones
97
+ # has_and_belongs_to_many :categories
98
+ # end
99
+ #
100
+ # The project class now has the following methods (and more) to ease the traversal and manipulation of its relationships:
101
+ # * <tt>Project#portfolio, Project#portfolio=(portfolio), Project#portfolio.nil?</tt>
102
+ # * <tt>Project#project_manager, Project#project_manager=(project_manager), Project#project_manager.nil?,</tt>
103
+ # * <tt>Project#milestones.empty?, Project#milestones.size, Project#milestones, Project#milestones<<(milestone),</tt>
104
+ # <tt>Project#milestones.delete(milestone), Project#milestones.find(milestone_id), Project#milestones.find(:all, options),</tt>
105
+ # <tt>Project#milestones.build, Project#milestones.create</tt>
106
+ # * <tt>Project#categories.empty?, Project#categories.size, Project#categories, Project#categories<<(category1),</tt>
107
+ # <tt>Project#categories.delete(category1)</tt>
108
+ #
109
+ # === A word of warning
110
+ #
111
+ # Don't create associations that have the same name as instance methods of ActiveRecord::Base. Since the association
112
+ # adds a method with that name to its model, it will override the inherited method and break things.
113
+ # For instance, +attributes+ and +connection+ would be bad choices for association names.
114
+ #
115
+ # == Auto-generated methods
116
+ #
117
+ # === Singular associations (one-to-one)
118
+ # | | belongs_to |
119
+ # generated methods | belongs_to | :polymorphic | has_one
120
+ # ----------------------------------+------------+--------------+---------
121
+ # #other | X | X | X
122
+ # #other=(other) | X | X | X
123
+ # #build_other(attributes={}) | X | | X
124
+ # #create_other(attributes={}) | X | | X
125
+ # #other.create!(attributes={}) | | | X
126
+ # #other.nil? | X | X |
127
+ #
128
+ # ===Collection associations (one-to-many / many-to-many)
129
+ # | | | has_many
130
+ # generated methods | habtm | has_many | :through
131
+ # ----------------------------------+-------+----------+----------
132
+ # #others | X | X | X
133
+ # #others=(other,other,...) | X | X | X
134
+ # #other_ids | X | X | X
135
+ # #other_ids=(id,id,...) | X | X | X
136
+ # #others<< | X | X | X
137
+ # #others.push | X | X | X
138
+ # #others.concat | X | X | X
139
+ # #others.build(attributes={}) | X | X | X
140
+ # #others.create(attributes={}) | X | X | X
141
+ # #others.create!(attributes={}) | X | X | X
142
+ # #others.size | X | X | X
143
+ # #others.length | X | X | X
144
+ # #others.count | X | X | X
145
+ # #others.sum(args*,&block) | X | X | X
146
+ # #others.empty? | X | X | X
147
+ # #others.clear | X | X | X
148
+ # #others.delete(other,other,...) | X | X | X
149
+ # #others.delete_all | X | X |
150
+ # #others.destroy_all | X | X | X
151
+ # #others.find(*args) | X | X | X
152
+ # #others.find_first | X | |
153
+ # #others.uniq | X | X | X
154
+ # #others.reset | X | X | X
155
+ #
156
+ # == Cardinality and associations
157
+ #
158
+ # Active Record associations can be used to describe one-to-one, one-to-many and many-to-many
159
+ # relationships between models. Each model uses an association to describe its role in
160
+ # the relation. The +belongs_to+ association is always used in the model that has
161
+ # the foreign key.
162
+ #
163
+ # === One-to-one
164
+ #
165
+ # Use +has_one+ in the base, and +belongs_to+ in the associated model.
166
+ #
167
+ # class Employee < ActiveRecord::Base
168
+ # has_one :office
169
+ # end
170
+ # class Office < ActiveRecord::Base
171
+ # belongs_to :employee # foreign key - employee_id
172
+ # end
173
+ #
174
+ # === One-to-many
175
+ #
176
+ # Use +has_many+ in the base, and +belongs_to+ in the associated model.
177
+ #
178
+ # class Manager < ActiveRecord::Base
179
+ # has_many :employees
180
+ # end
181
+ # class Employee < ActiveRecord::Base
182
+ # belongs_to :manager # foreign key - manager_id
183
+ # end
184
+ #
185
+ # === Many-to-many
186
+ #
187
+ # There are two ways to build a many-to-many relationship.
188
+ #
189
+ # The first way uses a +has_many+ association with the <tt>:through</tt> option and a join model, so
190
+ # there are two stages of associations.
191
+ #
192
+ # class Assignment < ActiveRecord::Base
193
+ # belongs_to :programmer # foreign key - programmer_id
194
+ # belongs_to :project # foreign key - project_id
195
+ # end
196
+ # class Programmer < ActiveRecord::Base
197
+ # has_many :assignments
198
+ # has_many :projects, :through => :assignments
199
+ # end
200
+ # class Project < ActiveRecord::Base
201
+ # has_many :assignments
202
+ # has_many :programmers, :through => :assignments
203
+ # end
204
+ #
205
+ # For the second way, use +has_and_belongs_to_many+ in both models. This requires a join table
206
+ # that has no corresponding model or primary key.
207
+ #
208
+ # class Programmer < ActiveRecord::Base
209
+ # has_and_belongs_to_many :projects # foreign keys in the join table
210
+ # end
211
+ # class Project < ActiveRecord::Base
212
+ # has_and_belongs_to_many :programmers # foreign keys in the join table
213
+ # end
214
+ #
215
+ # Choosing which way to build a many-to-many relationship is not always simple.
216
+ # If you need to work with the relationship model as its own entity,
217
+ # use <tt>has_many :through</tt>. Use +has_and_belongs_to_many+ when working with legacy schemas or when
218
+ # you never work directly with the relationship itself.
219
+ #
220
+ # == Is it a +belongs_to+ or +has_one+ association?
221
+ #
222
+ # Both express a 1-1 relationship. The difference is mostly where to place the foreign key, which goes on the table for the class
223
+ # declaring the +belongs_to+ relationship. Example:
224
+ #
225
+ # class User < ActiveRecord::Base
226
+ # # I reference an account.
227
+ # belongs_to :account
228
+ # end
229
+ #
230
+ # class Account < ActiveRecord::Base
231
+ # # One user references me.
232
+ # has_one :user
233
+ # end
234
+ #
235
+ # The tables for these classes could look something like:
236
+ #
237
+ # CREATE TABLE users (
238
+ # id int(11) NOT NULL auto_increment,
239
+ # account_id int(11) default NULL,
240
+ # name varchar default NULL,
241
+ # PRIMARY KEY (id)
242
+ # )
243
+ #
244
+ # CREATE TABLE accounts (
245
+ # id int(11) NOT NULL auto_increment,
246
+ # name varchar default NULL,
247
+ # PRIMARY KEY (id)
248
+ # )
249
+ #
250
+ # == Unsaved objects and associations
251
+ #
252
+ # You can manipulate objects and associations before they are saved to the database, but there is some special behavior you should be
253
+ # aware of, mostly involving the saving of associated objects.
254
+ #
255
+ # === One-to-one associations
256
+ #
257
+ # * Assigning an object to a +has_one+ association automatically saves that object and the object being replaced (if there is one), in
258
+ # order to update their primary keys - except if the parent object is unsaved (<tt>new_record? == true</tt>).
259
+ # * If either of these saves fail (due to one of the objects being invalid) the assignment statement returns +false+ and the assignment
260
+ # is cancelled.
261
+ # * If you wish to assign an object to a +has_one+ association without saving it, use the <tt>association.build</tt> method (documented below).
262
+ # * Assigning an object to a +belongs_to+ association does not save the object, since the foreign key field belongs on the parent. It
263
+ # does not save the parent either.
264
+ #
265
+ # === Collections
266
+ #
267
+ # * Adding an object to a collection (+has_many+ or +has_and_belongs_to_many+) automatically saves that object, except if the parent object
268
+ # (the owner of the collection) is not yet stored in the database.
269
+ # * If saving any of the objects being added to a collection (via <tt>push</tt> or similar) fails, then <tt>push</tt> returns +false+.
270
+ # * You can add an object to a collection without automatically saving it by using the <tt>collection.build</tt> method (documented below).
271
+ # * All unsaved (<tt>new_record? == true</tt>) members of the collection are automatically saved when the parent is saved.
272
+ #
273
+ # === Association callbacks
274
+ #
275
+ # Similar to the normal callbacks that hook into the lifecycle of an Active Record object, you can also define callbacks that get
276
+ # triggered when you add an object to or remove an object from an association collection. Example:
277
+ #
278
+ # class Project
279
+ # has_and_belongs_to_many :developers, :after_add => :evaluate_velocity
280
+ #
281
+ # def evaluate_velocity(developer)
282
+ # ...
283
+ # end
284
+ # end
285
+ #
286
+ # It's possible to stack callbacks by passing them as an array. Example:
287
+ #
288
+ # class Project
289
+ # has_and_belongs_to_many :developers, :after_add => [:evaluate_velocity, Proc.new { |p, d| p.shipping_date = Time.now}]
290
+ # end
291
+ #
292
+ # Possible callbacks are: +before_add+, +after_add+, +before_remove+ and +after_remove+.
293
+ #
294
+ # Should any of the +before_add+ callbacks throw an exception, the object does not get added to the collection. Same with
295
+ # the +before_remove+ callbacks; if an exception is thrown the object doesn't get removed.
296
+ #
297
+ # === Association extensions
298
+ #
299
+ # The proxy objects that control the access to associations can be extended through anonymous modules. This is especially
300
+ # beneficial for adding new finders, creators, and other factory-type methods that are only used as part of this association.
301
+ # Example:
302
+ #
303
+ # class Account < ActiveRecord::Base
304
+ # has_many :people do
305
+ # def find_or_create_by_name(name)
306
+ # first_name, last_name = name.split(" ", 2)
307
+ # find_or_create_by_first_name_and_last_name(first_name, last_name)
308
+ # end
309
+ # end
310
+ # end
311
+ #
312
+ # person = Account.find(:first).people.find_or_create_by_name("David Heinemeier Hansson")
313
+ # person.first_name # => "David"
314
+ # person.last_name # => "Heinemeier Hansson"
315
+ #
316
+ # If you need to share the same extensions between many associations, you can use a named extension module. Example:
317
+ #
318
+ # module FindOrCreateByNameExtension
319
+ # def find_or_create_by_name(name)
320
+ # first_name, last_name = name.split(" ", 2)
321
+ # find_or_create_by_first_name_and_last_name(first_name, last_name)
322
+ # end
323
+ # end
324
+ #
325
+ # class Account < ActiveRecord::Base
326
+ # has_many :people, :extend => FindOrCreateByNameExtension
327
+ # end
328
+ #
329
+ # class Company < ActiveRecord::Base
330
+ # has_many :people, :extend => FindOrCreateByNameExtension
331
+ # end
332
+ #
333
+ # If you need to use multiple named extension modules, you can specify an array of modules with the <tt>:extend</tt> option.
334
+ # In the case of name conflicts between methods in the modules, methods in modules later in the array supercede
335
+ # those earlier in the array. Example:
336
+ #
337
+ # class Account < ActiveRecord::Base
338
+ # has_many :people, :extend => [FindOrCreateByNameExtension, FindRecentExtension]
339
+ # end
340
+ #
341
+ # Some extensions can only be made to work with knowledge of the association proxy's internals.
342
+ # Extensions can access relevant state using accessors on the association proxy:
343
+ #
344
+ # * +proxy_owner+ - Returns the object the association is part of.
345
+ # * +proxy_reflection+ - Returns the reflection object that describes the association.
346
+ # * +proxy_target+ - Returns the associated object for +belongs_to+ and +has_one+, or the collection of associated objects for +has_many+ and +has_and_belongs_to_many+.
347
+ #
348
+ # === Association Join Models
349
+ #
350
+ # Has Many associations can be configured with the <tt>:through</tt> option to use an explicit join model to retrieve the data. This
351
+ # operates similarly to a +has_and_belongs_to_many+ association. The advantage is that you're able to add validations,
352
+ # callbacks, and extra attributes on the join model. Consider the following schema:
353
+ #
354
+ # class Author < ActiveRecord::Base
355
+ # has_many :authorships
356
+ # has_many :books, :through => :authorships
357
+ # end
358
+ #
359
+ # class Authorship < ActiveRecord::Base
360
+ # belongs_to :author
361
+ # belongs_to :book
362
+ # end
363
+ #
364
+ # @author = Author.find :first
365
+ # @author.authorships.collect { |a| a.book } # selects all books that the author's authorships belong to.
366
+ # @author.books # selects all books by using the Authorship join model
367
+ #
368
+ # You can also go through a +has_many+ association on the join model:
369
+ #
370
+ # class Firm < ActiveRecord::Base
371
+ # has_many :clients
372
+ # has_many :invoices, :through => :clients
373
+ # end
374
+ #
375
+ # class Client < ActiveRecord::Base
376
+ # belongs_to :firm
377
+ # has_many :invoices
378
+ # end
379
+ #
380
+ # class Invoice < ActiveRecord::Base
381
+ # belongs_to :client
382
+ # end
383
+ #
384
+ # @firm = Firm.find :first
385
+ # @firm.clients.collect { |c| c.invoices }.flatten # select all invoices for all clients of the firm
386
+ # @firm.invoices # selects all invoices by going through the Client join model.
387
+ #
388
+ # === Polymorphic Associations
389
+ #
390
+ # Polymorphic associations on models are not restricted on what types of models they can be associated with. Rather, they
391
+ # specify an interface that a +has_many+ association must adhere to.
392
+ #
393
+ # class Asset < ActiveRecord::Base
394
+ # belongs_to :attachable, :polymorphic => true
395
+ # end
396
+ #
397
+ # class Post < ActiveRecord::Base
398
+ # has_many :assets, :as => :attachable # The :as option specifies the polymorphic interface to use.
399
+ # end
400
+ #
401
+ # @asset.attachable = @post
402
+ #
403
+ # This works by using a type column in addition to a foreign key to specify the associated record. In the Asset example, you'd need
404
+ # an +attachable_id+ integer column and an +attachable_type+ string column.
405
+ #
406
+ # Using polymorphic associations in combination with single table inheritance (STI) is a little tricky. In order
407
+ # for the associations to work as expected, ensure that you store the base model for the STI models in the
408
+ # type column of the polymorphic association. To continue with the asset example above, suppose there are guest posts
409
+ # and member posts that use the posts table for STI. In this case, there must be a +type+ column in the posts table.
410
+ #
411
+ # class Asset < ActiveRecord::Base
412
+ # belongs_to :attachable, :polymorphic => true
413
+ #
414
+ # def attachable_type=(sType)
415
+ # super(sType.to_s.classify.constantize.base_class.to_s)
416
+ # end
417
+ # end
418
+ #
419
+ # class Post < ActiveRecord::Base
420
+ # # because we store "Post" in attachable_type now :dependent => :destroy will work
421
+ # has_many :assets, :as => :attachable, :dependent => :destroy
422
+ # end
423
+ #
424
+ # class GuestPost < Post
425
+ # end
426
+ #
427
+ # class MemberPost < Post
428
+ # end
429
+ #
430
+ # == Caching
431
+ #
432
+ # All of the methods are built on a simple caching principle that will keep the result of the last query around unless specifically
433
+ # instructed not to. The cache is even shared across methods to make it even cheaper to use the macro-added methods without
434
+ # worrying too much about performance at the first go. Example:
435
+ #
436
+ # project.milestones # fetches milestones from the database
437
+ # project.milestones.size # uses the milestone cache
438
+ # project.milestones.empty? # uses the milestone cache
439
+ # project.milestones(true).size # fetches milestones from the database
440
+ # project.milestones # uses the milestone cache
441
+ #
442
+ # == Eager loading of associations
443
+ #
444
+ # Eager loading is a way to find objects of a certain class and a number of named associations. This is
445
+ # one of the easiest ways of to prevent the dreaded 1+N problem in which fetching 100 posts that each need to display their author
446
+ # triggers 101 database queries. Through the use of eager loading, the 101 queries can be reduced to 2. Example:
447
+ #
448
+ # class Post < ActiveRecord::Base
449
+ # belongs_to :author
450
+ # has_many :comments
451
+ # end
452
+ #
453
+ # Consider the following loop using the class above:
454
+ #
455
+ # for post in Post.all
456
+ # puts "Post: " + post.title
457
+ # puts "Written by: " + post.author.name
458
+ # puts "Last comment on: " + post.comments.first.created_on
459
+ # end
460
+ #
461
+ # To iterate over these one hundred posts, we'll generate 201 database queries. Let's first just optimize it for retrieving the author:
462
+ #
463
+ # for post in Post.find(:all, :include => :author)
464
+ #
465
+ # This references the name of the +belongs_to+ association that also used the <tt>:author</tt> symbol. After loading the posts, find
466
+ # will collect the +author_id+ from each one and load all the referenced authors with one query. Doing so will cut down the number of queries from 201 to 102.
467
+ #
468
+ # We can improve upon the situation further by referencing both associations in the finder with:
469
+ #
470
+ # for post in Post.find(:all, :include => [ :author, :comments ])
471
+ #
472
+ # This will load all comments with a single query. This reduces the total number of queries to 3. More generally the number of queries
473
+ # will be 1 plus the number of associations named (except if some of the associations are polymorphic +belongs_to+ - see below).
474
+ #
475
+ # To include a deep hierarchy of associations, use a hash:
476
+ #
477
+ # for post in Post.find(:all, :include => [ :author, { :comments => { :author => :gravatar } } ])
478
+ #
479
+ # That'll grab not only all the comments but all their authors and gravatar pictures. You can mix and match
480
+ # symbols, arrays and hashes in any combination to describe the associations you want to load.
481
+ #
482
+ # All of this power shouldn't fool you into thinking that you can pull out huge amounts of data with no performance penalty just because you've reduced
483
+ # the number of queries. The database still needs to send all the data to Active Record and it still needs to be processed. So it's no
484
+ # catch-all for performance problems, but it's a great way to cut down on the number of queries in a situation as the one described above.
485
+ #
486
+ # Since only one table is loaded at a time, conditions or orders cannot reference tables other than the main one. If this is the case
487
+ # Active Record falls back to the previously used LEFT OUTER JOIN based strategy. For example
488
+ #
489
+ # Post.find(:all, :include => [ :author, :comments ], :conditions => ['comments.approved = ?', true])
490
+ #
491
+ # will result in a single SQL query with joins along the lines of: <tt>LEFT OUTER JOIN comments ON comments.post_id = posts.id</tt> and
492
+ # <tt>LEFT OUTER JOIN authors ON authors.id = posts.author_id</tt>. Note that using conditions like this can have unintended consequences.
493
+ # In the above example posts with no approved comments are not returned at all, because the conditions apply to the SQL statement as a whole
494
+ # and not just to the association. You must disambiguate column references for this fallback to happen, for example
495
+ # <tt>:order => "author.name DESC"</tt> will work but <tt>:order => "name DESC"</tt> will not.
496
+ #
497
+ # If you do want eagerload only some members of an association it is usually more natural to <tt>:include</tt> an association
498
+ # which has conditions defined on it:
499
+ #
500
+ # class Post < ActiveRecord::Base
501
+ # has_many :approved_comments, :class_name => 'Comment', :conditions => ['approved = ?', true]
502
+ # end
503
+ #
504
+ # Post.find(:all, :include => :approved_comments)
505
+ #
506
+ # will load posts and eager load the +approved_comments+ association, which contains only those comments that have been approved.
507
+ #
508
+ # When eager loaded, conditions are interpolated in the context of the model class, not the model instance. Conditions are lazily interpolated
509
+ # before the actual model exists.
510
+ #
511
+ # Eager loading is supported with polymorphic associations.
512
+ #
513
+ # class Address < ActiveRecord::Base
514
+ # belongs_to :addressable, :polymorphic => true
515
+ # end
516
+ #
517
+ # A call that tries to eager load the addressable model
518
+ #
519
+ # Address.find(:all, :include => :addressable)
520
+ #
521
+ # will execute one query to load the addresses and load the addressables with one query per addressable type.
522
+ # For example if all the addressables are either of class Person or Company then a total of 3 queries will be executed. The list of
523
+ # addressable types to load is determined on the back of the addresses loaded. This is not supported if Active Record has to fallback
524
+ # to the previous implementation of eager loading and will raise ActiveRecord::EagerLoadPolymorphicError. The reason is that the parent
525
+ # model's type is a column value so its corresponding table name cannot be put in the +FROM+/+JOIN+ clauses of that query.
526
+ #
527
+ # == Table Aliasing
528
+ #
529
+ # Active Record uses table aliasing in the case that a table is referenced multiple times in a join. If a table is referenced only once,
530
+ # the standard table name is used. The second time, the table is aliased as <tt>#{reflection_name}_#{parent_table_name}</tt>. Indexes are appended
531
+ # for any more successive uses of the table name.
532
+ #
533
+ # Post.find :all, :joins => :comments
534
+ # # => SELECT ... FROM posts INNER JOIN comments ON ...
535
+ # Post.find :all, :joins => :special_comments # STI
536
+ # # => SELECT ... FROM posts INNER JOIN comments ON ... AND comments.type = 'SpecialComment'
537
+ # Post.find :all, :joins => [:comments, :special_comments] # special_comments is the reflection name, posts is the parent table name
538
+ # # => SELECT ... FROM posts INNER JOIN comments ON ... INNER JOIN comments special_comments_posts
539
+ #
540
+ # Acts as tree example:
541
+ #
542
+ # TreeMixin.find :all, :joins => :children
543
+ # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
544
+ # TreeMixin.find :all, :joins => {:children => :parent}
545
+ # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
546
+ # INNER JOIN parents_mixins ...
547
+ # TreeMixin.find :all, :joins => {:children => {:parent => :children}}
548
+ # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
549
+ # INNER JOIN parents_mixins ...
550
+ # INNER JOIN mixins childrens_mixins_2
551
+ #
552
+ # Has and Belongs to Many join tables use the same idea, but add a <tt>_join</tt> suffix:
553
+ #
554
+ # Post.find :all, :joins => :categories
555
+ # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
556
+ # Post.find :all, :joins => {:categories => :posts}
557
+ # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
558
+ # INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories
559
+ # Post.find :all, :joins => {:categories => {:posts => :categories}}
560
+ # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
561
+ # INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories
562
+ # INNER JOIN categories_posts categories_posts_join INNER JOIN categories categories_posts_2
563
+ #
564
+ # If you wish to specify your own custom joins using a <tt>:joins</tt> option, those table names will take precedence over the eager associations:
565
+ #
566
+ # Post.find :all, :joins => :comments, :joins => "inner join comments ..."
567
+ # # => SELECT ... FROM posts INNER JOIN comments_posts ON ... INNER JOIN comments ...
568
+ # Post.find :all, :joins => [:comments, :special_comments], :joins => "inner join comments ..."
569
+ # # => SELECT ... FROM posts INNER JOIN comments comments_posts ON ...
570
+ # INNER JOIN comments special_comments_posts ...
571
+ # INNER JOIN comments ...
572
+ #
573
+ # Table aliases are automatically truncated according to the maximum length of table identifiers according to the specific database.
574
+ #
575
+ # == Modules
576
+ #
577
+ # By default, associations will look for objects within the current module scope. Consider:
578
+ #
579
+ # module MyApplication
580
+ # module Business
581
+ # class Firm < ActiveRecord::Base
582
+ # has_many :clients
583
+ # end
584
+ #
585
+ # class Company < ActiveRecord::Base; end
586
+ # end
587
+ # end
588
+ #
589
+ # When Firm#clients is called, it will in turn call <tt>MyApplication::Business::Company.find(firm.id)</tt>. If you want to associate
590
+ # with a class in another module scope, this can be done by specifying the complete class name. Example:
591
+ #
592
+ # module MyApplication
593
+ # module Business
594
+ # class Firm < ActiveRecord::Base; end
595
+ # end
596
+ #
597
+ # module Billing
598
+ # class Account < ActiveRecord::Base
599
+ # belongs_to :firm, :class_name => "MyApplication::Business::Firm"
600
+ # end
601
+ # end
602
+ # end
603
+ #
604
+ # == Type safety with <tt>ActiveRecord::AssociationTypeMismatch</tt>
605
+ #
606
+ # If you attempt to assign an object to an association that doesn't match the inferred or specified <tt>:class_name</tt>, you'll
607
+ # get an <tt>ActiveRecord::AssociationTypeMismatch</tt>.
608
+ #
609
+ # == Options
610
+ #
611
+ # All of the association macros can be specialized through options. This makes cases more complex than the simple and guessable ones
612
+ # possible.
613
+ module ClassMethods
614
+ # Adds the following methods for retrieval and query of collections of associated objects:
615
+ # +collection+ is replaced with the symbol passed as the first argument, so
616
+ # <tt>has_many :clients</tt> would add among others <tt>clients.empty?</tt>.
617
+ # * <tt>collection(force_reload = false)</tt> - Returns an array of all the associated objects.
618
+ # An empty array is returned if none are found.
619
+ # * <tt>collection<<(object, ...)</tt> - Adds one or more objects to the collection by setting their foreign keys to the collection's primary key.
620
+ # * <tt>collection.delete(object, ...)</tt> - Removes one or more objects from the collection by setting their foreign keys to +NULL+.
621
+ # This will also destroy the objects if they're declared as +belongs_to+ and dependent on this model.
622
+ # * <tt>collection=objects</tt> - Replaces the collections content by deleting and adding objects as appropriate.
623
+ # * <tt>collection_singular_ids</tt> - Returns an array of the associated objects' ids
624
+ # * <tt>collection_singular_ids=ids</tt> - Replace the collection with the objects identified by the primary keys in +ids+
625
+ # * <tt>collection.clear</tt> - Removes every object from the collection. This destroys the associated objects if they
626
+ # are associated with <tt>:dependent => :destroy</tt>, deletes them directly from the database if <tt>:dependent => :delete_all</tt>,
627
+ # otherwise sets their foreign keys to +NULL+.
628
+ # * <tt>collection.empty?</tt> - Returns +true+ if there are no associated objects.
629
+ # * <tt>collection.size</tt> - Returns the number of associated objects.
630
+ # * <tt>collection.find</tt> - Finds an associated object according to the same rules as Base.find.
631
+ # * <tt>collection.build(attributes = {}, ...)</tt> - Returns one or more new objects of the collection type that have been instantiated
632
+ # with +attributes+ and linked to this object through a foreign key, but have not yet been saved. *Note:* This only works if an
633
+ # associated object already exists, not if it's +nil+!
634
+ # * <tt>collection.create(attributes = {})</tt> - Returns a new object of the collection type that has been instantiated
635
+ # with +attributes+, linked to this object through a foreign key, and that has already been saved (if it passed the validation).
636
+ # *Note:* This only works if an associated object already exists, not if it's +nil+!
637
+ #
638
+ # Example: A Firm class declares <tt>has_many :clients</tt>, which will add:
639
+ # * <tt>Firm#clients</tt> (similar to <tt>Clients.find :all, :conditions => "firm_id = #{id}"</tt>)
640
+ # * <tt>Firm#clients<<</tt>
641
+ # * <tt>Firm#clients.delete</tt>
642
+ # * <tt>Firm#clients=</tt>
643
+ # * <tt>Firm#client_ids</tt>
644
+ # * <tt>Firm#client_ids=</tt>
645
+ # * <tt>Firm#clients.clear</tt>
646
+ # * <tt>Firm#clients.empty?</tt> (similar to <tt>firm.clients.size == 0</tt>)
647
+ # * <tt>Firm#clients.size</tt> (similar to <tt>Client.count "firm_id = #{id}"</tt>)
648
+ # * <tt>Firm#clients.find</tt> (similar to <tt>Client.find(id, :conditions => "firm_id = #{id}")</tt>)
649
+ # * <tt>Firm#clients.build</tt> (similar to <tt>Client.new("firm_id" => id)</tt>)
650
+ # * <tt>Firm#clients.create</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save; c</tt>)
651
+ # The declaration can also include an options hash to specialize the behavior of the association.
652
+ #
653
+ # Options are:
654
+ # * <tt>:class_name</tt> - Specify the class name of the association. Use it only if that name can't be inferred
655
+ # from the association name. So <tt>has_many :products</tt> will by default be linked to the Product class, but
656
+ # if the real class name is SpecialProduct, you'll have to specify it with this option.
657
+ # * <tt>:conditions</tt> - Specify the conditions that the associated objects must meet in order to be included as a +WHERE+
658
+ # SQL fragment, such as <tt>price > 5 AND name LIKE 'B%'</tt>. Record creations from the association are scoped if a hash
659
+ # is used. <tt>has_many :posts, :conditions => {:published => true}</tt> will create published posts with <tt>@blog.posts.create</tt>
660
+ # or <tt>@blog.posts.build</tt>.
661
+ # * <tt>:order</tt> - Specify the order in which the associated objects are returned as an <tt>ORDER BY</tt> SQL fragment,
662
+ # such as <tt>last_name, first_name DESC</tt>.
663
+ # * <tt>:foreign_key</tt> - Specify the foreign key used for the association. By default this is guessed to be the name
664
+ # of this class in lower-case and "_id" suffixed. So a Person class that makes a +has_many+ association will use "person_id"
665
+ # as the default <tt>:foreign_key</tt>.
666
+ # * <tt>:dependent</tt> - If set to <tt>:destroy</tt> all the associated objects are destroyed
667
+ # alongside this object by calling their +destroy+ method. If set to <tt>:delete_all</tt> all associated
668
+ # objects are deleted *without* calling their +destroy+ method. If set to <tt>:nullify</tt> all associated
669
+ # objects' foreign keys are set to +NULL+ *without* calling their +save+ callbacks. *Warning:* This option is ignored when also using
670
+ # the <tt>:through</tt> option.
671
+ # * <tt>:finder_sql</tt> - Specify a complete SQL statement to fetch the association. This is a good way to go for complex
672
+ # associations that depend on multiple tables. Note: When this option is used, +find_in_collection+ is _not_ added.
673
+ # * <tt>:counter_sql</tt> - Specify a complete SQL statement to fetch the size of the association. If <tt>:finder_sql</tt> is
674
+ # specified but not <tt>:counter_sql</tt>, <tt>:counter_sql</tt> will be generated by replacing <tt>SELECT ... FROM</tt> with <tt>SELECT COUNT(*) FROM</tt>.
675
+ # * <tt>:extend</tt> - Specify a named module for extending the proxy. See "Association extensions".
676
+ # * <tt>:include</tt> - Specify second-order associations that should be eager loaded when the collection is loaded.
677
+ # * <tt>:group</tt> - An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause.
678
+ # * <tt>:limit</tt> - An integer determining the limit on the number of rows that should be returned.
679
+ # * <tt>:offset</tt> - An integer determining the offset from where the rows should be fetched. So at 5, it would skip the first 4 rows.
680
+ # * <tt>:select</tt> - By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if you, for example, want to do a join
681
+ # but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will rise an error.
682
+ # * <tt>:as</tt> - Specifies a polymorphic interface (See <tt>belongs_to</tt>).
683
+ # * <tt>:through</tt> - Specifies a Join Model through which to perform the query. Options for <tt>:class_name</tt> and <tt>:foreign_key</tt>
684
+ # are ignored, as the association uses the source reflection. You can only use a <tt>:through</tt> query through a <tt>belongs_to</tt>
685
+ # or <tt>has_many</tt> association on the join model.
686
+ # * <tt>:source</tt> - Specifies the source association name used by <tt>has_many :through</tt> queries. Only use it if the name cannot be
687
+ # inferred from the association. <tt>has_many :subscribers, :through => :subscriptions</tt> will look for either <tt>:subscribers</tt> or
688
+ # <tt>:subscriber</tt> on Subscription, unless a <tt>:source</tt> is given.
689
+ # * <tt>:source_type</tt> - Specifies type of the source association used by <tt>has_many :through</tt> queries where the source
690
+ # association is a polymorphic +belongs_to+.
691
+ # * <tt>:uniq</tt> - If true, duplicates will be omitted from the collection. Useful in conjunction with <tt>:through</tt>.
692
+ # * <tt>:readonly</tt> - If true, all the associated objects are readonly through the association.
693
+ # * <tt>:validate</tt> - If false, don't validate the associated objects when saving the parent object. true by default.
694
+ #
695
+ # Option examples:
696
+ # has_many :comments, :order => "posted_on"
697
+ # has_many :comments, :include => :author
698
+ # has_many :people, :class_name => "Person", :conditions => "deleted = 0", :order => "name"
699
+ # has_many :tracks, :order => "position", :dependent => :destroy
700
+ # has_many :comments, :dependent => :nullify
701
+ # has_many :tags, :as => :taggable
702
+ # has_many :reports, :readonly => true
703
+ # has_many :subscribers, :through => :subscriptions, :source => :user
704
+ # has_many :subscribers, :class_name => "Person", :finder_sql =>
705
+ # 'SELECT DISTINCT people.* ' +
706
+ # 'FROM people p, post_subscriptions ps ' +
707
+ # 'WHERE ps.post_id = #{id} AND ps.person_id = p.id ' +
708
+ # 'ORDER BY p.first_name'
709
+ def has_many(association_id, options = {}, &extension)
710
+ reflection = create_has_many_reflection(association_id, options, &extension)
711
+
712
+ configure_dependency_for_has_many(reflection)
713
+
714
+ add_multiple_associated_validation_callbacks(reflection.name) unless options[:validate] == false
715
+ add_multiple_associated_save_callbacks(reflection.name)
716
+ add_association_callbacks(reflection.name, reflection.options)
717
+
718
+ if options[:through]
719
+ collection_accessor_methods(reflection, HasManyThroughAssociation)
720
+ else
721
+ collection_accessor_methods(reflection, HasManyAssociation)
722
+ end
723
+ end
724
+
725
+ # Adds the following methods for retrieval and query of a single associated object:
726
+ # +association+ is replaced with the symbol passed as the first argument, so
727
+ # <tt>has_one :manager</tt> would add among others <tt>manager.nil?</tt>.
728
+ # * <tt>association(force_reload = false)</tt> - Returns the associated object. +nil+ is returned if none is found.
729
+ # * <tt>association=(associate)</tt> - Assigns the associate object, extracts the primary key, sets it as the foreign key,
730
+ # and saves the associate object.
731
+ # * <tt>association.nil?</tt> - Returns +true+ if there is no associated object.
732
+ # * <tt>build_association(attributes = {})</tt> - Returns a new object of the associated type that has been instantiated
733
+ # with +attributes+ and linked to this object through a foreign key, but has not yet been saved. Note: This ONLY works if
734
+ # an association already exists. It will NOT work if the association is +nil+.
735
+ # * <tt>create_association(attributes = {})</tt> - Returns a new object of the associated type that has been instantiated
736
+ # with +attributes+, linked to this object through a foreign key, and that has already been saved (if it passed the validation).
737
+ #
738
+ # Example: An Account class declares <tt>has_one :beneficiary</tt>, which will add:
739
+ # * <tt>Account#beneficiary</tt> (similar to <tt>Beneficiary.find(:first, :conditions => "account_id = #{id}")</tt>)
740
+ # * <tt>Account#beneficiary=(beneficiary)</tt> (similar to <tt>beneficiary.account_id = account.id; beneficiary.save</tt>)
741
+ # * <tt>Account#beneficiary.nil?</tt>
742
+ # * <tt>Account#build_beneficiary</tt> (similar to <tt>Beneficiary.new("account_id" => id)</tt>)
743
+ # * <tt>Account#create_beneficiary</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save; b</tt>)
744
+ #
745
+ # The declaration can also include an options hash to specialize the behavior of the association.
746
+ #
747
+ # Options are:
748
+ # * <tt>:class_name</tt> - Specify the class name of the association. Use it only if that name can't be inferred
749
+ # from the association name. So <tt>has_one :manager</tt> will by default be linked to the Manager class, but
750
+ # if the real class name is Person, you'll have to specify it with this option.
751
+ # * <tt>:conditions</tt> - Specify the conditions that the associated object must meet in order to be included as a +WHERE+
752
+ # SQL fragment, such as <tt>rank = 5</tt>.
753
+ # * <tt>:order</tt> - Specify the order in which the associated objects are returned as an <tt>ORDER BY</tt> SQL fragment,
754
+ # such as <tt>last_name, first_name DESC</tt>.
755
+ # * <tt>:dependent</tt> - If set to <tt>:destroy</tt>, the associated object is destroyed when this object is. If set to
756
+ # <tt>:delete</tt>, the associated object is deleted *without* calling its destroy method. If set to <tt>:nullify</tt>, the associated
757
+ # object's foreign key is set to +NULL+. Also, association is assigned.
758
+ # * <tt>:foreign_key</tt> - Specify the foreign key used for the association. By default this is guessed to be the name
759
+ # of this class in lower-case and "_id" suffixed. So a Person class that makes a +has_one+ association will use "person_id"
760
+ # as the default <tt>:foreign_key</tt>.
761
+ # * <tt>:include</tt> - Specify second-order associations that should be eager loaded when this object is loaded.
762
+ # * <tt>:as</tt> - Specifies a polymorphic interface (See <tt>belongs_to</tt>).
763
+ # * <tt>:select</tt> - By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if, for example, you want to do a join
764
+ # but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will raise an error.
765
+ # * <tt>:through</tt>: Specifies a Join Model through which to perform the query. Options for <tt>:class_name</tt> and <tt>:foreign_key</tt>
766
+ # are ignored, as the association uses the source reflection. You can only use a <tt>:through</tt> query through a
767
+ # <tt>has_one</tt> or <tt>belongs_to</tt> association on the join model.
768
+ # * <tt>:source</tt> - Specifies the source association name used by <tt>has_one :through</tt> queries. Only use it if the name cannot be
769
+ # inferred from the association. <tt>has_one :favorite, :through => :favorites</tt> will look for a
770
+ # <tt>:favorite</tt> on Favorite, unless a <tt>:source</tt> is given.
771
+ # * <tt>:source_type</tt> - Specifies type of the source association used by <tt>has_one :through</tt> queries where the source
772
+ # association is a polymorphic +belongs_to+.
773
+ # * <tt>:readonly</tt> - If true, the associated object is readonly through the association.
774
+ # * <tt>:validate</tt> - If false, don't validate the associated object when saving the parent object. +false+ by default.
775
+ #
776
+ # Option examples:
777
+ # has_one :credit_card, :dependent => :destroy # destroys the associated credit card
778
+ # has_one :credit_card, :dependent => :nullify # updates the associated records foreign key value to NULL rather than destroying it
779
+ # has_one :last_comment, :class_name => "Comment", :order => "posted_on"
780
+ # has_one :project_manager, :class_name => "Person", :conditions => "role = 'project_manager'"
781
+ # has_one :attachment, :as => :attachable
782
+ # has_one :boss, :readonly => :true
783
+ # has_one :club, :through => :membership
784
+ # has_one :primary_address, :through => :addressables, :conditions => ["addressable.primary = ?", true], :source => :addressable
785
+ def has_one(association_id, options = {})
786
+ if options[:through]
787
+ reflection = create_has_one_through_reflection(association_id, options)
788
+ association_accessor_methods(reflection, ActiveRecord::Associations::HasOneThroughAssociation)
789
+ else
790
+ reflection = create_has_one_reflection(association_id, options)
791
+
792
+ ivar = "@#{reflection.name}"
793
+
794
+ method_name = "has_one_after_save_for_#{reflection.name}".to_sym
795
+ define_method(method_name) do
796
+ association = instance_variable_get("#{ivar}") if instance_variable_defined?("#{ivar}")
797
+
798
+ if !association.nil? && (new_record? || association.new_record? || association["#{reflection.primary_key_name}"] != id)
799
+ association["#{reflection.primary_key_name}"] = id
800
+ association.save(true)
801
+ end
802
+ end
803
+ after_save method_name
804
+
805
+ add_single_associated_validation_callbacks(reflection.name) if options[:validate] == true
806
+ association_accessor_methods(reflection, HasOneAssociation)
807
+ association_constructor_method(:build, reflection, HasOneAssociation)
808
+ association_constructor_method(:create, reflection, HasOneAssociation)
809
+
810
+ configure_dependency_for_has_one(reflection)
811
+ end
812
+ end
813
+
814
+ # Adds the following methods for retrieval and query for a single associated object for which this object holds an id:
815
+ # +association+ is replaced with the symbol passed as the first argument, so
816
+ # <tt>belongs_to :author</tt> would add among others <tt>author.nil?</tt>.
817
+ # * <tt>association(force_reload = false)</tt> - Returns the associated object. +nil+ is returned if none is found.
818
+ # * <tt>association=(associate)</tt> - Assigns the associate object, extracts the primary key, and sets it as the foreign key.
819
+ # * <tt>association.nil?</tt> - Returns +true+ if there is no associated object.
820
+ # * <tt>build_association(attributes = {})</tt> - Returns a new object of the associated type that has been instantiated
821
+ # with +attributes+ and linked to this object through a foreign key, but has not yet been saved.
822
+ # * <tt>create_association(attributes = {})</tt> - Returns a new object of the associated type that has been instantiated
823
+ # with +attributes+, linked to this object through a foreign key, and that has already been saved (if it passed the validation).
824
+ #
825
+ # Example: A Post class declares <tt>belongs_to :author</tt>, which will add:
826
+ # * <tt>Post#author</tt> (similar to <tt>Author.find(author_id)</tt>)
827
+ # * <tt>Post#author=(author)</tt> (similar to <tt>post.author_id = author.id</tt>)
828
+ # * <tt>Post#author?</tt> (similar to <tt>post.author == some_author</tt>)
829
+ # * <tt>Post#author.nil?</tt>
830
+ # * <tt>Post#build_author</tt> (similar to <tt>post.author = Author.new</tt>)
831
+ # * <tt>Post#create_author</tt> (similar to <tt>post.author = Author.new; post.author.save; post.author</tt>)
832
+ # The declaration can also include an options hash to specialize the behavior of the association.
833
+ #
834
+ # Options are:
835
+ # * <tt>:class_name</tt> - Specify the class name of the association. Use it only if that name can't be inferred
836
+ # from the association name. So <tt>has_one :author</tt> will by default be linked to the Author class, but
837
+ # if the real class name is Person, you'll have to specify it with this option.
838
+ # * <tt>:conditions</tt> - Specify the conditions that the associated object must meet in order to be included as a +WHERE+
839
+ # SQL fragment, such as <tt>authorized = 1</tt>.
840
+ # * <tt>:select</tt> - By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if, for example, you want to do a join
841
+ # but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will raise an error.
842
+ # * <tt>:foreign_key</tt> - Specify the foreign key used for the association. By default this is guessed to be the name
843
+ # of the association with an "_id" suffix. So a class that defines a <tt>belongs_to :person</tt> association will use
844
+ # "person_id" as the default <tt>:foreign_key</tt>. Similarly, <tt>belongs_to :favorite_person, :class_name => "Person"</tt>
845
+ # will use a foreign key of "favorite_person_id".
846
+ # * <tt>:dependent</tt> - If set to <tt>:destroy</tt>, the associated object is destroyed when this object is. If set to
847
+ # <tt>:delete</tt>, the associated object is deleted *without* calling its destroy method. This option should not be specified when
848
+ # <tt>belongs_to</tt> is used in conjunction with a <tt>has_many</tt> relationship on another class because of the potential to leave
849
+ # orphaned records behind.
850
+ # * <tt>:counter_cache</tt> - Caches the number of belonging objects on the associate class through the use of +increment_counter+
851
+ # and +decrement_counter+. The counter cache is incremented when an object of this class is created and decremented when it's
852
+ # destroyed. This requires that a column named <tt>#{table_name}_count</tt> (such as +comments_count+ for a belonging Comment class)
853
+ # is used on the associate class (such as a Post class). You can also specify a custom counter cache column by providing
854
+ # a column name instead of a +true+/+false+ value to this option (e.g., <tt>:counter_cache => :my_custom_counter</tt>.)
855
+ # When creating a counter cache column, the database statement or migration must specify a default value of <tt>0</tt>, failing to do
856
+ # this results in a counter with +NULL+ value, which will never increment.
857
+ # Note: Specifying a counter cache will add it to that model's list of readonly attributes using +attr_readonly+.
858
+ # * <tt>:include</tt> - Specify second-order associations that should be eager loaded when this object is loaded.
859
+ # * <tt>:polymorphic</tt> - Specify this association is a polymorphic association by passing +true+.
860
+ # Note: If you've enabled the counter cache, then you may want to add the counter cache attribute
861
+ # to the +attr_readonly+ list in the associated classes (e.g. <tt>class Post; attr_readonly :comments_count; end</tt>).
862
+ # * <tt>:readonly</tt> - If true, the associated object is readonly through the association.
863
+ # * <tt>:validate</tt> - If false, don't validate the associated objects when saving the parent object. +false+ by default.
864
+ #
865
+ # Option examples:
866
+ # belongs_to :firm, :foreign_key => "client_of"
867
+ # belongs_to :author, :class_name => "Person", :foreign_key => "author_id"
868
+ # belongs_to :valid_coupon, :class_name => "Coupon", :foreign_key => "coupon_id",
869
+ # :conditions => 'discounts > #{payments_count}'
870
+ # belongs_to :attachable, :polymorphic => true
871
+ # belongs_to :project, :readonly => true
872
+ # belongs_to :post, :counter_cache => true
873
+ def belongs_to(association_id, options = {})
874
+ reflection = create_belongs_to_reflection(association_id, options)
875
+
876
+ ivar = "@#{reflection.name}"
877
+
878
+ if reflection.options[:polymorphic]
879
+ association_accessor_methods(reflection, BelongsToPolymorphicAssociation)
880
+
881
+ method_name = "polymorphic_belongs_to_before_save_for_#{reflection.name}".to_sym
882
+ define_method(method_name) do
883
+ association = instance_variable_get("#{ivar}") if instance_variable_defined?("#{ivar}")
884
+
885
+ if association && association.target
886
+ if association.new_record?
887
+ association.save(true)
888
+ end
889
+
890
+ if association.updated?
891
+ self["#{reflection.primary_key_name}"] = association.id
892
+ self["#{reflection.options[:foreign_type]}"] = association.class.base_class.name.to_s
893
+ end
894
+ end
895
+ end
896
+ before_save method_name
897
+ else
898
+ association_accessor_methods(reflection, BelongsToAssociation)
899
+ association_constructor_method(:build, reflection, BelongsToAssociation)
900
+ association_constructor_method(:create, reflection, BelongsToAssociation)
901
+
902
+ method_name = "belongs_to_before_save_for_#{reflection.name}".to_sym
903
+ define_method(method_name) do
904
+ association = instance_variable_get("#{ivar}") if instance_variable_defined?("#{ivar}")
905
+
906
+ if !association.nil?
907
+ if association.new_record?
908
+ association.save(true)
909
+ end
910
+
911
+ if association.updated?
912
+ self["#{reflection.primary_key_name}"] = association.id
913
+ end
914
+ end
915
+ end
916
+ before_save method_name
917
+ end
918
+
919
+ # Create the callbacks to update counter cache
920
+ if options[:counter_cache]
921
+ cache_column = options[:counter_cache] == true ?
922
+ "#{self.to_s.underscore.pluralize}_count" :
923
+ options[:counter_cache]
924
+
925
+ method_name = "belongs_to_counter_cache_after_create_for_#{reflection.name}".to_sym
926
+ define_method(method_name) do
927
+ association = send("#{reflection.name}")
928
+ association.class.increment_counter("#{cache_column}", send("#{reflection.primary_key_name}")) unless association.nil?
929
+ end
930
+ after_create method_name
931
+
932
+ method_name = "belongs_to_counter_cache_before_destroy_for_#{reflection.name}".to_sym
933
+ define_method(method_name) do
934
+ association = send("#{reflection.name}")
935
+ association.class.decrement_counter("#{cache_column}", send("#{reflection.primary_key_name}")) unless association.nil?
936
+ end
937
+ before_destroy method_name
938
+
939
+ module_eval(
940
+ "#{reflection.class_name}.send(:attr_readonly,\"#{cache_column}\".intern) if defined?(#{reflection.class_name}) && #{reflection.class_name}.respond_to?(:attr_readonly)"
941
+ )
942
+ end
943
+
944
+ add_single_associated_validation_callbacks(reflection.name) if options[:validate] == true
945
+
946
+ configure_dependency_for_belongs_to(reflection)
947
+ end
948
+
949
+ # Associates two classes via an intermediate join table. Unless the join table is explicitly specified as
950
+ # an option, it is guessed using the lexical order of the class names. So a join between Developer and Project
951
+ # will give the default join table name of "developers_projects" because "D" outranks "P". Note that this precedence
952
+ # is calculated using the <tt><</tt> operator for String. This means that if the strings are of different lengths,
953
+ # and the strings are equal when compared up to the shortest length, then the longer string is considered of higher
954
+ # lexical precedence than the shorter one. For example, one would expect the tables "paper_boxes" and "papers"
955
+ # to generate a join table name of "papers_paper_boxes" because of the length of the name "paper_boxes",
956
+ # but it in fact generates a join table name of "paper_boxes_papers". Be aware of this caveat, and use the
957
+ # custom <tt>:join_table</tt> option if you need to.
958
+ #
959
+ # Deprecated: Any additional fields added to the join table will be placed as attributes when pulling records out through
960
+ # +has_and_belongs_to_many+ associations. Records returned from join tables with additional attributes will be marked as
961
+ # readonly (because we can't save changes to the additional attributes). It's strongly recommended that you upgrade any
962
+ # associations with attributes to a real join model (see introduction).
963
+ #
964
+ # Adds the following methods for retrieval and query:
965
+ # +collection+ is replaced with the symbol passed as the first argument, so
966
+ # <tt>has_and_belongs_to_many :categories</tt> would add among others <tt>categories.empty?</tt>.
967
+ # * <tt>collection(force_reload = false)</tt> - Returns an array of all the associated objects.
968
+ # An empty array is returned if none are found.
969
+ # * <tt>collection<<(object, ...)</tt> - Adds one or more objects to the collection by creating associations in the join table
970
+ # (<tt>collection.push</tt> and <tt>collection.concat</tt> are aliases to this method).
971
+ # * <tt>collection.delete(object, ...)</tt> - Removes one or more objects from the collection by removing their associations from the join table.
972
+ # This does not destroy the objects.
973
+ # * <tt>collection=objects</tt> - Replaces the collection's content by deleting and adding objects as appropriate.
974
+ # * <tt>collection_singular_ids</tt> - Returns an array of the associated objects' ids.
975
+ # * <tt>collection_singular_ids=ids</tt> - Replace the collection by the objects identified by the primary keys in +ids+.
976
+ # * <tt>collection.clear</tt> - Removes every object from the collection. This does not destroy the objects.
977
+ # * <tt>collection.empty?</tt> - Returns +true+ if there are no associated objects.
978
+ # * <tt>collection.size</tt> - Returns the number of associated objects.
979
+ # * <tt>collection.find(id)</tt> - Finds an associated object responding to the +id+ and that
980
+ # meets the condition that it has to be associated with this object.
981
+ # * <tt>collection.build(attributes = {})</tt> - Returns a new object of the collection type that has been instantiated
982
+ # with +attributes+ and linked to this object through the join table, but has not yet been saved.
983
+ # * <tt>collection.create(attributes = {})</tt> - Returns a new object of the collection type that has been instantiated
984
+ # with +attributes+, linked to this object through the join table, and that has already been saved (if it passed the validation).
985
+ #
986
+ # Example: A Developer class declares <tt>has_and_belongs_to_many :projects</tt>, which will add:
987
+ # * <tt>Developer#projects</tt>
988
+ # * <tt>Developer#projects<<</tt>
989
+ # * <tt>Developer#projects.delete</tt>
990
+ # * <tt>Developer#projects=</tt>
991
+ # * <tt>Developer#project_ids</tt>
992
+ # * <tt>Developer#project_ids=</tt>
993
+ # * <tt>Developer#projects.clear</tt>
994
+ # * <tt>Developer#projects.empty?</tt>
995
+ # * <tt>Developer#projects.size</tt>
996
+ # * <tt>Developer#projects.find(id)</tt>
997
+ # * <tt>Developer#projects.build</tt> (similar to <tt>Project.new("project_id" => id)</tt>)
998
+ # * <tt>Developer#projects.create</tt> (similar to <tt>c = Project.new("project_id" => id); c.save; c</tt>)
999
+ # The declaration may include an options hash to specialize the behavior of the association.
1000
+ #
1001
+ # Options are:
1002
+ # * <tt>:class_name</tt> - Specify the class name of the association. Use it only if that name can't be inferred
1003
+ # from the association name. So <tt>has_and_belongs_to_many :projects</tt> will by default be linked to the
1004
+ # Project class, but if the real class name is SuperProject, you'll have to specify it with this option.
1005
+ # * <tt>:join_table</tt> - Specify the name of the join table if the default based on lexical order isn't what you want.
1006
+ # WARNING: If you're overwriting the table name of either class, the +table_name+ method MUST be declared underneath any
1007
+ # +has_and_belongs_to_many+ declaration in order to work.
1008
+ # * <tt>:foreign_key</tt> - Specify the foreign key used for the association. By default this is guessed to be the name
1009
+ # of this class in lower-case and "_id" suffixed. So a Person class that makes a +has_and_belongs_to_many+ association
1010
+ # will use "person_id" as the default <tt>:foreign_key</tt>.
1011
+ # * <tt>:association_foreign_key</tt> - Specify the association foreign key used for the association. By default this is
1012
+ # guessed to be the name of the associated class in lower-case and "_id" suffixed. So if the associated class is Project,
1013
+ # the +has_and_belongs_to_many+ association will use "project_id" as the default <tt>:association_foreign_key</tt>.
1014
+ # * <tt>:conditions</tt> - Specify the conditions that the associated object must meet in order to be included as a +WHERE+
1015
+ # SQL fragment, such as <tt>authorized = 1</tt>. Record creations from the association are scoped if a hash is used.
1016
+ # <tt>has_many :posts, :conditions => {:published => true}</tt> will create published posts with <tt>@blog.posts.create</tt>
1017
+ # or <tt>@blog.posts.build</tt>.
1018
+ # * <tt>:order</tt> - Specify the order in which the associated objects are returned as an <tt>ORDER BY</tt> SQL fragment,
1019
+ # such as <tt>last_name, first_name DESC</tt>
1020
+ # * <tt>:uniq</tt> - If true, duplicate associated objects will be ignored by accessors and query methods.
1021
+ # * <tt>:finder_sql</tt> - Overwrite the default generated SQL statement used to fetch the association with a manual statement
1022
+ # * <tt>:delete_sql</tt> - Overwrite the default generated SQL statement used to remove links between the associated
1023
+ # classes with a manual statement.
1024
+ # * <tt>:insert_sql</tt> - Overwrite the default generated SQL statement used to add links between the associated classes
1025
+ # with a manual statement.
1026
+ # * <tt>:extend</tt> - Anonymous module for extending the proxy, see "Association extensions".
1027
+ # * <tt>:include</tt> - Specify second-order associations that should be eager loaded when the collection is loaded.
1028
+ # * <tt>:group</tt> - An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause.
1029
+ # * <tt>:limit</tt> - An integer determining the limit on the number of rows that should be returned.
1030
+ # * <tt>:offset</tt> - An integer determining the offset from where the rows should be fetched. So at 5, it would skip the first 4 rows.
1031
+ # * <tt>:select</tt> - By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if, for example, you want to do a join
1032
+ # but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will raise an error.
1033
+ # * <tt>:readonly</tt> - If true, all the associated objects are readonly through the association.
1034
+ # * <tt>:validate</tt> - If false, don't validate the associated objects when saving the parent object. +true+ by default.
1035
+ #
1036
+ # Option examples:
1037
+ # has_and_belongs_to_many :projects
1038
+ # has_and_belongs_to_many :projects, :include => [ :milestones, :manager ]
1039
+ # has_and_belongs_to_many :nations, :class_name => "Country"
1040
+ # has_and_belongs_to_many :categories, :join_table => "prods_cats"
1041
+ # has_and_belongs_to_many :categories, :readonly => true
1042
+ # has_and_belongs_to_many :active_projects, :join_table => 'developers_projects', :delete_sql =>
1043
+ # 'DELETE FROM developers_projects WHERE active=1 AND developer_id = #{id} AND project_id = #{record.id}'
1044
+ def has_and_belongs_to_many(association_id, options = {}, &extension)
1045
+ reflection = create_has_and_belongs_to_many_reflection(association_id, options, &extension)
1046
+
1047
+ add_multiple_associated_validation_callbacks(reflection.name) unless options[:validate] == false
1048
+ add_multiple_associated_save_callbacks(reflection.name)
1049
+ collection_accessor_methods(reflection, HasAndBelongsToManyAssociation)
1050
+
1051
+ # Don't use a before_destroy callback since users' before_destroy
1052
+ # callbacks will be executed after the association is wiped out.
1053
+ old_method = "destroy_without_habtm_shim_for_#{reflection.name}"
1054
+ class_eval <<-end_eval unless method_defined?(old_method)
1055
+ alias_method :#{old_method}, :destroy_without_callbacks
1056
+ def destroy_without_callbacks
1057
+ #{reflection.name}.clear
1058
+ #{old_method}
1059
+ end
1060
+ end_eval
1061
+
1062
+ add_association_callbacks(reflection.name, options)
1063
+ end
1064
+
1065
+ private
1066
+ # Generate a join table name from two provided tables names.
1067
+ # The order of names in join name is determined by lexical precedence.
1068
+ # join_table_name("members", "clubs")
1069
+ # => "clubs_members"
1070
+ # join_table_name("members", "special_clubs")
1071
+ # => "members_special_clubs"
1072
+ def join_table_name(first_table_name, second_table_name)
1073
+ if first_table_name < second_table_name
1074
+ join_table = "#{first_table_name}_#{second_table_name}"
1075
+ else
1076
+ join_table = "#{second_table_name}_#{first_table_name}"
1077
+ end
1078
+
1079
+ table_name_prefix + join_table + table_name_suffix
1080
+ end
1081
+
1082
+ def association_accessor_methods(reflection, association_proxy_class)
1083
+ ivar = "@#{reflection.name}"
1084
+
1085
+ define_method(reflection.name) do |*params|
1086
+ force_reload = params.first unless params.empty?
1087
+
1088
+ association = instance_variable_get(ivar) if instance_variable_defined?(ivar)
1089
+
1090
+ if association.nil? || force_reload
1091
+ association = association_proxy_class.new(self, reflection)
1092
+ retval = association.reload
1093
+ if retval.nil? and association_proxy_class == BelongsToAssociation
1094
+ instance_variable_set(ivar, nil)
1095
+ return nil
1096
+ end
1097
+ instance_variable_set(ivar, association)
1098
+ end
1099
+
1100
+ association.target.nil? ? nil : association
1101
+ end
1102
+
1103
+ define_method("#{reflection.name}=") do |new_value|
1104
+ association = instance_variable_get(ivar) if instance_variable_defined?(ivar)
1105
+
1106
+ if association.nil? || association.target != new_value
1107
+ association = association_proxy_class.new(self, reflection)
1108
+ end
1109
+
1110
+ if association_proxy_class == HasOneThroughAssociation
1111
+ association.create_through_record(new_value)
1112
+ self.send(reflection.name, new_value)
1113
+ else
1114
+ association.replace(new_value)
1115
+ instance_variable_set(ivar, new_value.nil? ? nil : association)
1116
+ end
1117
+ end
1118
+
1119
+ define_method("set_#{reflection.name}_target") do |target|
1120
+ return if target.nil? and association_proxy_class == BelongsToAssociation
1121
+ association = association_proxy_class.new(self, reflection)
1122
+ association.target = target
1123
+ instance_variable_set(ivar, association)
1124
+ end
1125
+ end
1126
+
1127
+ def collection_reader_method(reflection, association_proxy_class)
1128
+ define_method(reflection.name) do |*params|
1129
+ ivar = "@#{reflection.name}"
1130
+
1131
+ force_reload = params.first unless params.empty?
1132
+ association = instance_variable_get(ivar) if instance_variable_defined?(ivar)
1133
+
1134
+ unless association.respond_to?(:loaded?)
1135
+ association = association_proxy_class.new(self, reflection)
1136
+ instance_variable_set(ivar, association)
1137
+ end
1138
+
1139
+ association.reload if force_reload
1140
+
1141
+ association
1142
+ end
1143
+
1144
+ define_method("#{reflection.name.to_s.singularize}_ids") do
1145
+ send(reflection.name).map(&:id)
1146
+ end
1147
+ end
1148
+
1149
+ def collection_accessor_methods(reflection, association_proxy_class, writer = true)
1150
+ collection_reader_method(reflection, association_proxy_class)
1151
+
1152
+ if writer
1153
+ define_method("#{reflection.name}=") do |new_value|
1154
+ # Loads proxy class instance (defined in collection_reader_method) if not already loaded
1155
+ association = send(reflection.name)
1156
+ association.replace(new_value)
1157
+ association
1158
+ end
1159
+
1160
+ define_method("#{reflection.name.to_s.singularize}_ids=") do |new_value|
1161
+ ids = (new_value || []).reject { |nid| nid.blank? }
1162
+ send("#{reflection.name}=", reflection.class_name.constantize.find(ids))
1163
+ end
1164
+ end
1165
+ end
1166
+
1167
+ def add_single_associated_validation_callbacks(association_name)
1168
+ method_name = "validate_associated_records_for_#{association_name}".to_sym
1169
+ define_method(method_name) do
1170
+ association = instance_variable_get("@#{association_name}")
1171
+ if !association.nil?
1172
+ errors.add "#{association_name}" unless association.target.nil? || association.valid?
1173
+ end
1174
+ end
1175
+
1176
+ validate method_name
1177
+ end
1178
+
1179
+ def add_multiple_associated_validation_callbacks(association_name)
1180
+ method_name = "validate_associated_records_for_#{association_name}".to_sym
1181
+ ivar = "@#{association_name}"
1182
+
1183
+ define_method(method_name) do
1184
+ association = instance_variable_get(ivar) if instance_variable_defined?(ivar)
1185
+
1186
+ if association.respond_to?(:loaded?)
1187
+ if new_record?
1188
+ association
1189
+ elsif association.loaded?
1190
+ association.select { |record| record.new_record? }
1191
+ else
1192
+ association.target.select { |record| record.new_record? }
1193
+ end.each do |record|
1194
+ errors.add "#{association_name}" unless record.valid?
1195
+ end
1196
+ end
1197
+ end
1198
+
1199
+ validate method_name
1200
+ end
1201
+
1202
+ def add_multiple_associated_save_callbacks(association_name)
1203
+ ivar = "@#{association_name}"
1204
+
1205
+ method_name = "before_save_associated_records_for_#{association_name}".to_sym
1206
+ define_method(method_name) do
1207
+ @new_record_before_save = new_record?
1208
+ true
1209
+ end
1210
+ before_save method_name
1211
+
1212
+ method_name = "after_create_or_update_associated_records_for_#{association_name}".to_sym
1213
+ define_method(method_name) do
1214
+ association = instance_variable_get("#{ivar}") if instance_variable_defined?("#{ivar}")
1215
+
1216
+ records_to_save = if @new_record_before_save
1217
+ association
1218
+ elsif association.respond_to?(:loaded?) && association.loaded?
1219
+ association.select { |record| record.new_record? }
1220
+ elsif association.respond_to?(:loaded?) && !association.loaded?
1221
+ association.target.select { |record| record.new_record? }
1222
+ else
1223
+ []
1224
+ end
1225
+ records_to_save.each { |record| association.send(:insert_record, record) } unless records_to_save.blank?
1226
+
1227
+ # reconstruct the SQL queries now that we know the owner's id
1228
+ association.send(:construct_sql) if association.respond_to?(:construct_sql)
1229
+ end
1230
+
1231
+ # Doesn't use after_save as that would save associations added in after_create/after_update twice
1232
+ after_create method_name
1233
+ after_update method_name
1234
+ end
1235
+
1236
+ def association_constructor_method(constructor, reflection, association_proxy_class)
1237
+ define_method("#{constructor}_#{reflection.name}") do |*params|
1238
+ ivar = "@#{reflection.name}"
1239
+
1240
+ attributees = params.first unless params.empty?
1241
+ replace_existing = params[1].nil? ? true : params[1]
1242
+ association = instance_variable_get(ivar) if instance_variable_defined?(ivar)
1243
+
1244
+ if association.nil?
1245
+ association = association_proxy_class.new(self, reflection)
1246
+ instance_variable_set(ivar, association)
1247
+ end
1248
+
1249
+ if association_proxy_class == HasOneAssociation
1250
+ association.send(constructor, attributees, replace_existing)
1251
+ else
1252
+ association.send(constructor, attributees)
1253
+ end
1254
+ end
1255
+ end
1256
+
1257
+ def find_with_associations(options = {})
1258
+ catch :invalid_query do
1259
+ join_dependency = JoinDependency.new(self, merge_includes(scope(:find, :include), options[:include]), options[:joins])
1260
+ rows = select_all_rows(options, join_dependency)
1261
+ return join_dependency.instantiate(rows)
1262
+ end
1263
+ []
1264
+ end
1265
+
1266
+ # See HasManyAssociation#delete_records. Dependent associations
1267
+ # delete children, otherwise foreign key is set to NULL.
1268
+ def configure_dependency_for_has_many(reflection)
1269
+ if reflection.options.include?(:dependent)
1270
+ # Add polymorphic type if the :as option is present
1271
+ dependent_conditions = []
1272
+ dependent_conditions << "#{reflection.primary_key_name} = \#{record.quoted_id}"
1273
+ dependent_conditions << "#{reflection.options[:as]}_type = '#{base_class.name}'" if reflection.options[:as]
1274
+ dependent_conditions << sanitize_sql(reflection.options[:conditions]) if reflection.options[:conditions]
1275
+ dependent_conditions = dependent_conditions.collect {|where| "(#{where})" }.join(" AND ")
1276
+
1277
+ case reflection.options[:dependent]
1278
+ when :destroy
1279
+ method_name = "has_many_dependent_destroy_for_#{reflection.name}".to_sym
1280
+ define_method(method_name) do
1281
+ send("#{reflection.name}").each { |o| o.destroy }
1282
+ end
1283
+ before_destroy method_name
1284
+ when :delete_all
1285
+ module_eval "before_destroy { |record| #{reflection.class_name}.delete_all(%(#{dependent_conditions})) }"
1286
+ when :nullify
1287
+ module_eval "before_destroy { |record| #{reflection.class_name}.update_all(%(#{reflection.primary_key_name} = NULL), %(#{dependent_conditions})) }"
1288
+ else
1289
+ raise ArgumentError, "The :dependent option expects either :destroy, :delete_all, or :nullify (#{reflection.options[:dependent].inspect})"
1290
+ end
1291
+ end
1292
+ end
1293
+
1294
+ def configure_dependency_for_has_one(reflection)
1295
+ if reflection.options.include?(:dependent)
1296
+ case reflection.options[:dependent]
1297
+ when :destroy
1298
+ method_name = "has_one_dependent_destroy_for_#{reflection.name}".to_sym
1299
+ define_method(method_name) do
1300
+ association = send("#{reflection.name}")
1301
+ association.destroy unless association.nil?
1302
+ end
1303
+ before_destroy method_name
1304
+ when :delete
1305
+ method_name = "has_one_dependent_delete_for_#{reflection.name}".to_sym
1306
+ define_method(method_name) do
1307
+ association = send("#{reflection.name}")
1308
+ association.class.delete(association.id) unless association.nil?
1309
+ end
1310
+ before_destroy method_name
1311
+ when :nullify
1312
+ method_name = "has_one_dependent_nullify_for_#{reflection.name}".to_sym
1313
+ define_method(method_name) do
1314
+ association = send("#{reflection.name}")
1315
+ association.update_attribute("#{reflection.primary_key_name}", nil) unless association.nil?
1316
+ end
1317
+ before_destroy method_name
1318
+ else
1319
+ raise ArgumentError, "The :dependent option expects either :destroy, :delete or :nullify (#{reflection.options[:dependent].inspect})"
1320
+ end
1321
+ end
1322
+ end
1323
+
1324
+ def configure_dependency_for_belongs_to(reflection)
1325
+ if reflection.options.include?(:dependent)
1326
+ case reflection.options[:dependent]
1327
+ when :destroy
1328
+ method_name = "belongs_to_dependent_destroy_for_#{reflection.name}".to_sym
1329
+ define_method(method_name) do
1330
+ association = send("#{reflection.name}")
1331
+ association.destroy unless association.nil?
1332
+ end
1333
+ before_destroy method_name
1334
+ when :delete
1335
+ method_name = "belongs_to_dependent_delete_for_#{reflection.name}".to_sym
1336
+ define_method(method_name) do
1337
+ association = send("#{reflection.name}")
1338
+ association.class.delete(association.id) unless association.nil?
1339
+ end
1340
+ before_destroy method_name
1341
+ else
1342
+ raise ArgumentError, "The :dependent option expects either :destroy or :delete (#{reflection.options[:dependent].inspect})"
1343
+ end
1344
+ end
1345
+ end
1346
+
1347
+ def create_has_many_reflection(association_id, options, &extension)
1348
+ options.assert_valid_keys(
1349
+ :class_name, :table_name, :foreign_key,
1350
+ :dependent,
1351
+ :select, :conditions, :include, :order, :group, :limit, :offset,
1352
+ :as, :through, :source, :source_type,
1353
+ :uniq,
1354
+ :finder_sql, :counter_sql,
1355
+ :before_add, :after_add, :before_remove, :after_remove,
1356
+ :extend, :readonly,
1357
+ :validate
1358
+ )
1359
+
1360
+ options[:extend] = create_extension_modules(association_id, extension, options[:extend])
1361
+
1362
+ create_reflection(:has_many, association_id, options, self)
1363
+ end
1364
+
1365
+ def create_has_one_reflection(association_id, options)
1366
+ options.assert_valid_keys(
1367
+ :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :readonly, :validate
1368
+ )
1369
+
1370
+ create_reflection(:has_one, association_id, options, self)
1371
+ end
1372
+
1373
+ def create_has_one_through_reflection(association_id, options)
1374
+ options.assert_valid_keys(
1375
+ :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :through, :source, :source_type, :validate
1376
+ )
1377
+ create_reflection(:has_one, association_id, options, self)
1378
+ end
1379
+
1380
+ def create_belongs_to_reflection(association_id, options)
1381
+ options.assert_valid_keys(
1382
+ :class_name, :foreign_key, :foreign_type, :remote, :select, :conditions, :include, :dependent,
1383
+ :counter_cache, :extend, :polymorphic, :readonly, :validate
1384
+ )
1385
+
1386
+ reflection = create_reflection(:belongs_to, association_id, options, self)
1387
+
1388
+ if options[:polymorphic]
1389
+ reflection.options[:foreign_type] ||= reflection.class_name.underscore + "_type"
1390
+ end
1391
+
1392
+ reflection
1393
+ end
1394
+
1395
+ def create_has_and_belongs_to_many_reflection(association_id, options, &extension)
1396
+ options.assert_valid_keys(
1397
+ :class_name, :table_name, :join_table, :foreign_key, :association_foreign_key,
1398
+ :select, :conditions, :include, :order, :group, :limit, :offset,
1399
+ :uniq,
1400
+ :finder_sql, :delete_sql, :insert_sql,
1401
+ :before_add, :after_add, :before_remove, :after_remove,
1402
+ :extend, :readonly,
1403
+ :validate
1404
+ )
1405
+
1406
+ options[:extend] = create_extension_modules(association_id, extension, options[:extend])
1407
+
1408
+ reflection = create_reflection(:has_and_belongs_to_many, association_id, options, self)
1409
+
1410
+ reflection.options[:join_table] ||= join_table_name(undecorated_table_name(self.to_s), undecorated_table_name(reflection.class_name))
1411
+
1412
+ reflection
1413
+ end
1414
+
1415
+ def reflect_on_included_associations(associations)
1416
+ [ associations ].flatten.collect { |association| reflect_on_association(association.to_s.intern) }
1417
+ end
1418
+
1419
+ def guard_against_unlimitable_reflections(reflections, options)
1420
+ if (options[:offset] || options[:limit]) && !using_limitable_reflections?(reflections)
1421
+ raise(
1422
+ ConfigurationError,
1423
+ "You can not use offset and limit together with has_many or has_and_belongs_to_many associations"
1424
+ )
1425
+ end
1426
+ end
1427
+
1428
+ def select_all_rows(options, join_dependency)
1429
+ connection.select_all(
1430
+ construct_finder_sql_with_included_associations(options, join_dependency),
1431
+ "#{name} Load Including Associations"
1432
+ )
1433
+ end
1434
+
1435
+ def construct_finder_sql_with_included_associations(options, join_dependency)
1436
+ scope = scope(:find)
1437
+ sql = "SELECT #{column_aliases(join_dependency)} FROM #{(scope && scope[:from]) || options[:from] || quoted_table_name} "
1438
+ sql << join_dependency.join_associations.collect{|join| join.association_join }.join
1439
+
1440
+ add_joins!(sql, options, scope)
1441
+ add_conditions!(sql, options[:conditions], scope)
1442
+ add_limited_ids_condition!(sql, options, join_dependency) if !using_limitable_reflections?(join_dependency.reflections) && ((scope && scope[:limit]) || options[:limit])
1443
+
1444
+ add_group!(sql, options[:group], scope)
1445
+ add_order!(sql, options[:order], scope)
1446
+ add_limit!(sql, options, scope) if using_limitable_reflections?(join_dependency.reflections)
1447
+ add_lock!(sql, options, scope)
1448
+
1449
+ return sanitize_sql(sql)
1450
+ end
1451
+
1452
+ def add_limited_ids_condition!(sql, options, join_dependency)
1453
+ unless (id_list = select_limited_ids_list(options, join_dependency)).empty?
1454
+ sql << "#{condition_word(sql)} #{connection.quote_table_name table_name}.#{primary_key} IN (#{id_list}) "
1455
+ else
1456
+ throw :invalid_query
1457
+ end
1458
+ end
1459
+
1460
+ def select_limited_ids_list(options, join_dependency)
1461
+ pk = columns_hash[primary_key]
1462
+
1463
+ connection.select_all(
1464
+ construct_finder_sql_for_association_limiting(options, join_dependency),
1465
+ "#{name} Load IDs For Limited Eager Loading"
1466
+ ).collect { |row| connection.quote(row[primary_key], pk) }.join(", ")
1467
+ end
1468
+
1469
+ def construct_finder_sql_for_association_limiting(options, join_dependency)
1470
+ scope = scope(:find)
1471
+
1472
+ # Only join tables referenced in order or conditions since this is particularly slow on the pre-query.
1473
+ tables_from_conditions = conditions_tables(options)
1474
+ tables_from_order = order_tables(options)
1475
+ all_tables = tables_from_conditions + tables_from_order
1476
+ distinct_join_associations = all_tables.uniq.map{|table|
1477
+ join_dependency.joins_for_table_name(table)
1478
+ }.flatten.compact.uniq
1479
+
1480
+ order = options[:order]
1481
+ if scoped_order = (scope && scope[:order])
1482
+ order = order ? "#{order}, #{scoped_order}" : scoped_order
1483
+ end
1484
+
1485
+ is_distinct = !options[:joins].blank? || include_eager_conditions?(options, tables_from_conditions) || include_eager_order?(options, tables_from_order)
1486
+ sql = "SELECT "
1487
+ if is_distinct
1488
+ sql << connection.distinct("#{connection.quote_table_name table_name}.#{primary_key}", order)
1489
+ else
1490
+ sql << primary_key
1491
+ end
1492
+ sql << " FROM #{connection.quote_table_name table_name} "
1493
+
1494
+ if is_distinct
1495
+ sql << distinct_join_associations.collect(&:association_join).join
1496
+ add_joins!(sql, options, scope)
1497
+ end
1498
+
1499
+ add_conditions!(sql, options[:conditions], scope)
1500
+ add_group!(sql, options[:group], scope)
1501
+
1502
+ if order && is_distinct
1503
+ connection.add_order_by_for_association_limiting!(sql, :order => order)
1504
+ else
1505
+ add_order!(sql, options[:order], scope)
1506
+ end
1507
+
1508
+ add_limit!(sql, options, scope)
1509
+
1510
+ return sanitize_sql(sql)
1511
+ end
1512
+
1513
+ def conditions_tables(options)
1514
+ # look in both sets of conditions
1515
+ conditions = [scope(:find, :conditions), options[:conditions]].inject([]) do |all, cond|
1516
+ case cond
1517
+ when nil then all
1518
+ when Array then all << cond.first
1519
+ else all << cond
1520
+ end
1521
+ end
1522
+ conditions.join(' ').scan(/([\.a-zA-Z_]+).?\./).flatten
1523
+ end
1524
+
1525
+ def order_tables(options)
1526
+ order = [options[:order], scope(:find, :order) ].join(", ")
1527
+ return [] unless order && order.is_a?(String)
1528
+ order.scan(/([\.a-zA-Z_]+).?\./).flatten
1529
+ end
1530
+
1531
+ def selects_tables(options)
1532
+ select = options[:select]
1533
+ return [] unless select && select.is_a?(String)
1534
+ select.scan(/"?([\.a-zA-Z_]+)"?.?\./).flatten
1535
+ end
1536
+
1537
+ # Checks if the conditions reference a table other than the current model table
1538
+ def include_eager_conditions?(options, tables = nil)
1539
+ ((tables || conditions_tables(options)) - [table_name]).any?
1540
+ end
1541
+
1542
+ # Checks if the query order references a table other than the current model's table.
1543
+ def include_eager_order?(options, tables = nil)
1544
+ ((tables || order_tables(options)) - [table_name]).any?
1545
+ end
1546
+
1547
+ def include_eager_select?(options)
1548
+ (selects_tables(options) - [table_name]).any?
1549
+ end
1550
+
1551
+ def references_eager_loaded_tables?(options)
1552
+ include_eager_order?(options) || include_eager_conditions?(options) || include_eager_select?(options)
1553
+ end
1554
+
1555
+ def using_limitable_reflections?(reflections)
1556
+ reflections.reject { |r| [ :belongs_to, :has_one ].include?(r.macro) }.length.zero?
1557
+ end
1558
+
1559
+ def column_aliases(join_dependency)
1560
+ join_dependency.joins.collect{|join| join.column_names_with_alias.collect{|column_name, aliased_name|
1561
+ "#{connection.quote_table_name join.aliased_table_name}.#{connection.quote_column_name column_name} AS #{aliased_name}"}}.flatten.join(", ")
1562
+ end
1563
+
1564
+ def add_association_callbacks(association_name, options)
1565
+ callbacks = %w(before_add after_add before_remove after_remove)
1566
+ callbacks.each do |callback_name|
1567
+ full_callback_name = "#{callback_name}_for_#{association_name}"
1568
+ defined_callbacks = options[callback_name.to_sym]
1569
+ if options.has_key?(callback_name.to_sym)
1570
+ class_inheritable_reader full_callback_name.to_sym
1571
+ write_inheritable_attribute(full_callback_name.to_sym, [defined_callbacks].flatten)
1572
+ else
1573
+ write_inheritable_attribute(full_callback_name.to_sym, [])
1574
+ end
1575
+ end
1576
+ end
1577
+
1578
+ def condition_word(sql)
1579
+ sql =~ /where/i ? " AND " : "WHERE "
1580
+ end
1581
+
1582
+ def create_extension_modules(association_id, block_extension, extensions)
1583
+ if block_extension
1584
+ extension_module_name = "#{self.to_s}#{association_id.to_s.camelize}AssociationExtension"
1585
+
1586
+ silence_warnings do
1587
+ Object.const_set(extension_module_name, Module.new(&block_extension))
1588
+ end
1589
+ Array(extensions).push(extension_module_name.constantize)
1590
+ else
1591
+ Array(extensions)
1592
+ end
1593
+ end
1594
+
1595
+ class JoinDependency # :nodoc:
1596
+ attr_reader :joins, :reflections, :table_aliases
1597
+
1598
+ def initialize(base, associations, joins)
1599
+ @joins = [JoinBase.new(base, joins)]
1600
+ @associations = associations
1601
+ @reflections = []
1602
+ @base_records_hash = {}
1603
+ @base_records_in_order = []
1604
+ @table_aliases = Hash.new { |aliases, table| aliases[table] = 0 }
1605
+ @table_aliases[base.table_name] = 1
1606
+ build(associations)
1607
+ end
1608
+
1609
+ def join_associations
1610
+ @joins[1..-1].to_a
1611
+ end
1612
+
1613
+ def join_base
1614
+ @joins[0]
1615
+ end
1616
+
1617
+ def instantiate(rows)
1618
+ rows.each_with_index do |row, i|
1619
+ primary_id = join_base.record_id(row)
1620
+ unless @base_records_hash[primary_id]
1621
+ @base_records_in_order << (@base_records_hash[primary_id] = join_base.instantiate(row))
1622
+ end
1623
+ construct(@base_records_hash[primary_id], @associations, join_associations.dup, row)
1624
+ end
1625
+ remove_duplicate_results!(join_base.active_record, @base_records_in_order, @associations)
1626
+ return @base_records_in_order
1627
+ end
1628
+
1629
+ def remove_duplicate_results!(base, records, associations)
1630
+ case associations
1631
+ when Symbol, String
1632
+ reflection = base.reflections[associations]
1633
+ if reflection && [:has_many, :has_and_belongs_to_many].include?(reflection.macro)
1634
+ records.each { |record| record.send(reflection.name).target.uniq! }
1635
+ end
1636
+ when Array
1637
+ associations.each do |association|
1638
+ remove_duplicate_results!(base, records, association)
1639
+ end
1640
+ when Hash
1641
+ associations.keys.each do |name|
1642
+ reflection = base.reflections[name]
1643
+ is_collection = [:has_many, :has_and_belongs_to_many].include?(reflection.macro)
1644
+
1645
+ parent_records = records.map do |record|
1646
+ descendant = record.send(reflection.name)
1647
+ next unless descendant
1648
+ descendant.target.uniq! if is_collection
1649
+ descendant
1650
+ end.flatten.compact
1651
+
1652
+ remove_duplicate_results!(reflection.class_name.constantize, parent_records, associations[name]) unless parent_records.empty?
1653
+ end
1654
+ end
1655
+ end
1656
+
1657
+ def join_for_table_name(table_name)
1658
+ join = (@joins.select{|j|j.aliased_table_name == table_name.gsub(/^\"(.*)\"$/){$1} }.first) rescue nil
1659
+ return join unless join.nil?
1660
+ @joins.select{|j|j.is_a?(JoinAssociation) && j.aliased_join_table_name == table_name.gsub(/^\"(.*)\"$/){$1} }.first rescue nil
1661
+ end
1662
+
1663
+ def joins_for_table_name(table_name)
1664
+ join = join_for_table_name(table_name)
1665
+ result = nil
1666
+ if join && join.is_a?(JoinAssociation)
1667
+ result = [join]
1668
+ if join.parent && join.parent.is_a?(JoinAssociation)
1669
+ result = joins_for_table_name(join.parent.aliased_table_name) +
1670
+ result
1671
+ end
1672
+ end
1673
+ result
1674
+ end
1675
+
1676
+ protected
1677
+ def build(associations, parent = nil)
1678
+ parent ||= @joins.last
1679
+ case associations
1680
+ when Symbol, String
1681
+ reflection = parent.reflections[associations.to_s.intern] or
1682
+ raise ConfigurationError, "Association named '#{ associations }' was not found; perhaps you misspelled it?"
1683
+ @reflections << reflection
1684
+ @joins << build_join_association(reflection, parent)
1685
+ when Array
1686
+ associations.each do |association|
1687
+ build(association, parent)
1688
+ end
1689
+ when Hash
1690
+ associations.keys.sort{|a,b|a.to_s<=>b.to_s}.each do |name|
1691
+ build(name, parent)
1692
+ build(associations[name])
1693
+ end
1694
+ else
1695
+ raise ConfigurationError, associations.inspect
1696
+ end
1697
+ end
1698
+
1699
+ # overridden in InnerJoinDependency subclass
1700
+ def build_join_association(reflection, parent)
1701
+ JoinAssociation.new(reflection, self, parent)
1702
+ end
1703
+
1704
+ def construct(parent, associations, joins, row)
1705
+ case associations
1706
+ when Symbol, String
1707
+ while (join = joins.shift).reflection.name.to_s != associations.to_s
1708
+ raise ConfigurationError, "Not Enough Associations" if joins.empty?
1709
+ end
1710
+ construct_association(parent, join, row)
1711
+ when Array
1712
+ associations.each do |association|
1713
+ construct(parent, association, joins, row)
1714
+ end
1715
+ when Hash
1716
+ associations.keys.sort{|a,b|a.to_s<=>b.to_s}.each do |name|
1717
+ association = construct_association(parent, joins.shift, row)
1718
+ construct(association, associations[name], joins, row) if association
1719
+ end
1720
+ else
1721
+ raise ConfigurationError, associations.inspect
1722
+ end
1723
+ end
1724
+
1725
+ def construct_association(record, join, row)
1726
+ case join.reflection.macro
1727
+ when :has_many, :has_and_belongs_to_many
1728
+ collection = record.send(join.reflection.name)
1729
+ collection.loaded
1730
+
1731
+ return nil if record.id.to_s != join.parent.record_id(row).to_s or row[join.aliased_primary_key].nil?
1732
+ association = join.instantiate(row)
1733
+ collection.target.push(association)
1734
+ when :has_one
1735
+ return if record.id.to_s != join.parent.record_id(row).to_s
1736
+ return if record.instance_variable_defined?("@#{join.reflection.name}")
1737
+ association = join.instantiate(row) unless row[join.aliased_primary_key].nil?
1738
+ record.send("set_#{join.reflection.name}_target", association)
1739
+ when :belongs_to
1740
+ return if record.id.to_s != join.parent.record_id(row).to_s or row[join.aliased_primary_key].nil?
1741
+ association = join.instantiate(row)
1742
+ record.send("set_#{join.reflection.name}_target", association)
1743
+ else
1744
+ raise ConfigurationError, "unknown macro: #{join.reflection.macro}"
1745
+ end
1746
+ return association
1747
+ end
1748
+
1749
+ class JoinBase # :nodoc:
1750
+ attr_reader :active_record, :table_joins
1751
+ delegate :table_name, :column_names, :primary_key, :reflections, :sanitize_sql, :to => :active_record
1752
+
1753
+ def initialize(active_record, joins = nil)
1754
+ @active_record = active_record
1755
+ @cached_record = {}
1756
+ @table_joins = joins
1757
+ end
1758
+
1759
+ def aliased_prefix
1760
+ "t0"
1761
+ end
1762
+
1763
+ def aliased_primary_key
1764
+ "#{ aliased_prefix }_r0"
1765
+ end
1766
+
1767
+ def aliased_table_name
1768
+ active_record.table_name
1769
+ end
1770
+
1771
+ def column_names_with_alias
1772
+ unless defined?(@column_names_with_alias)
1773
+ @column_names_with_alias = []
1774
+
1775
+ ([primary_key] + (column_names - [primary_key])).each_with_index do |column_name, i|
1776
+ @column_names_with_alias << [column_name, "#{ aliased_prefix }_r#{ i }"]
1777
+ end
1778
+ end
1779
+
1780
+ @column_names_with_alias
1781
+ end
1782
+
1783
+ def extract_record(row)
1784
+ column_names_with_alias.inject({}){|record, (cn, an)| record[cn] = row[an]; record}
1785
+ end
1786
+
1787
+ def record_id(row)
1788
+ row[aliased_primary_key]
1789
+ end
1790
+
1791
+ def instantiate(row)
1792
+ @cached_record[record_id(row)] ||= active_record.send(:instantiate, extract_record(row))
1793
+ end
1794
+ end
1795
+
1796
+ class JoinAssociation < JoinBase # :nodoc:
1797
+ attr_reader :reflection, :parent, :aliased_table_name, :aliased_prefix, :aliased_join_table_name, :parent_table_name
1798
+ delegate :options, :klass, :through_reflection, :source_reflection, :to => :reflection
1799
+
1800
+ def initialize(reflection, join_dependency, parent = nil)
1801
+ reflection.check_validity!
1802
+ if reflection.options[:polymorphic]
1803
+ raise EagerLoadPolymorphicError.new(reflection)
1804
+ end
1805
+
1806
+ super(reflection.klass)
1807
+ @join_dependency = join_dependency
1808
+ @parent = parent
1809
+ @reflection = reflection
1810
+ @aliased_prefix = "t#{ join_dependency.joins.size }"
1811
+ @parent_table_name = parent.active_record.table_name
1812
+ @aliased_table_name = aliased_table_name_for(table_name)
1813
+
1814
+ if reflection.macro == :has_and_belongs_to_many
1815
+ @aliased_join_table_name = aliased_table_name_for(reflection.options[:join_table], "_join")
1816
+ end
1817
+
1818
+ if [:has_many, :has_one].include?(reflection.macro) && reflection.options[:through]
1819
+ @aliased_join_table_name = aliased_table_name_for(reflection.through_reflection.klass.table_name, "_join")
1820
+ end
1821
+ end
1822
+
1823
+ def association_join
1824
+ connection = reflection.active_record.connection
1825
+ join = case reflection.macro
1826
+ when :has_and_belongs_to_many
1827
+ " #{join_type} %s ON %s.%s = %s.%s " % [
1828
+ table_alias_for(options[:join_table], aliased_join_table_name),
1829
+ connection.quote_table_name(aliased_join_table_name),
1830
+ options[:foreign_key] || reflection.active_record.to_s.foreign_key,
1831
+ connection.quote_table_name(parent.aliased_table_name),
1832
+ reflection.active_record.primary_key] +
1833
+ " #{join_type} %s ON %s.%s = %s.%s " % [
1834
+ table_name_and_alias,
1835
+ connection.quote_table_name(aliased_table_name),
1836
+ klass.primary_key,
1837
+ connection.quote_table_name(aliased_join_table_name),
1838
+ options[:association_foreign_key] || klass.to_s.foreign_key
1839
+ ]
1840
+ when :has_many, :has_one
1841
+ case
1842
+ when reflection.options[:through]
1843
+ through_conditions = through_reflection.options[:conditions] ? "AND #{interpolate_sql(sanitize_sql(through_reflection.options[:conditions]))}" : ''
1844
+
1845
+ jt_foreign_key = jt_as_extra = jt_source_extra = jt_sti_extra = nil
1846
+ first_key = second_key = as_extra = nil
1847
+
1848
+ if through_reflection.options[:as] # has_many :through against a polymorphic join
1849
+ jt_foreign_key = through_reflection.options[:as].to_s + '_id'
1850
+ jt_as_extra = " AND %s.%s = %s" % [
1851
+ connection.quote_table_name(aliased_join_table_name),
1852
+ connection.quote_column_name(through_reflection.options[:as].to_s + '_type'),
1853
+ klass.quote_value(parent.active_record.base_class.name)
1854
+ ]
1855
+ else
1856
+ jt_foreign_key = through_reflection.primary_key_name
1857
+ end
1858
+
1859
+ case source_reflection.macro
1860
+ when :has_many
1861
+ if source_reflection.options[:as]
1862
+ first_key = "#{source_reflection.options[:as]}_id"
1863
+ second_key = options[:foreign_key] || primary_key
1864
+ as_extra = " AND %s.%s = %s" % [
1865
+ connection.quote_table_name(aliased_table_name),
1866
+ connection.quote_column_name("#{source_reflection.options[:as]}_type"),
1867
+ klass.quote_value(source_reflection.active_record.base_class.name)
1868
+ ]
1869
+ else
1870
+ first_key = through_reflection.klass.base_class.to_s.foreign_key
1871
+ second_key = options[:foreign_key] || primary_key
1872
+ end
1873
+
1874
+ unless through_reflection.klass.descends_from_active_record?
1875
+ jt_sti_extra = " AND %s.%s = %s" % [
1876
+ connection.quote_table_name(aliased_join_table_name),
1877
+ connection.quote_column_name(through_reflection.active_record.inheritance_column),
1878
+ through_reflection.klass.quote_value(through_reflection.klass.sti_name)]
1879
+ end
1880
+ when :belongs_to
1881
+ first_key = primary_key
1882
+ if reflection.options[:source_type]
1883
+ second_key = source_reflection.association_foreign_key
1884
+ jt_source_extra = " AND %s.%s = %s" % [
1885
+ connection.quote_table_name(aliased_join_table_name),
1886
+ connection.quote_column_name(reflection.source_reflection.options[:foreign_type]),
1887
+ klass.quote_value(reflection.options[:source_type])
1888
+ ]
1889
+ else
1890
+ second_key = source_reflection.primary_key_name
1891
+ end
1892
+ end
1893
+
1894
+ " #{join_type} %s ON (%s.%s = %s.%s%s%s%s) " % [
1895
+ table_alias_for(through_reflection.klass.table_name, aliased_join_table_name),
1896
+ connection.quote_table_name(parent.aliased_table_name),
1897
+ connection.quote_column_name(parent.primary_key),
1898
+ connection.quote_table_name(aliased_join_table_name),
1899
+ connection.quote_column_name(jt_foreign_key),
1900
+ jt_as_extra, jt_source_extra, jt_sti_extra
1901
+ ] +
1902
+ " #{join_type} %s ON (%s.%s = %s.%s%s) " % [
1903
+ table_name_and_alias,
1904
+ connection.quote_table_name(aliased_table_name),
1905
+ connection.quote_column_name(first_key),
1906
+ connection.quote_table_name(aliased_join_table_name),
1907
+ connection.quote_column_name(second_key),
1908
+ as_extra
1909
+ ]
1910
+
1911
+ when reflection.options[:as] && [:has_many, :has_one].include?(reflection.macro)
1912
+ " #{join_type} %s ON %s.%s = %s.%s AND %s.%s = %s" % [
1913
+ table_name_and_alias,
1914
+ connection.quote_table_name(aliased_table_name),
1915
+ "#{reflection.options[:as]}_id",
1916
+ connection.quote_table_name(parent.aliased_table_name),
1917
+ parent.primary_key,
1918
+ connection.quote_table_name(aliased_table_name),
1919
+ "#{reflection.options[:as]}_type",
1920
+ klass.quote_value(parent.active_record.base_class.name)
1921
+ ]
1922
+ else
1923
+ foreign_key = options[:foreign_key] || reflection.active_record.name.foreign_key
1924
+ " #{join_type} %s ON %s.%s = %s.%s " % [
1925
+ table_name_and_alias,
1926
+ aliased_table_name,
1927
+ foreign_key,
1928
+ parent.aliased_table_name,
1929
+ parent.primary_key
1930
+ ]
1931
+ end
1932
+ when :belongs_to
1933
+ " #{join_type} %s ON %s.%s = %s.%s " % [
1934
+ table_name_and_alias,
1935
+ connection.quote_table_name(aliased_table_name),
1936
+ reflection.klass.primary_key,
1937
+ connection.quote_table_name(parent.aliased_table_name),
1938
+ options[:foreign_key] || reflection.primary_key_name
1939
+ ]
1940
+ else
1941
+ ""
1942
+ end || ''
1943
+ join << %(AND %s) % [
1944
+ klass.send(:type_condition, aliased_table_name)] unless klass.descends_from_active_record?
1945
+
1946
+ [through_reflection, reflection].each do |ref|
1947
+ join << "AND #{interpolate_sql(sanitize_sql(ref.options[:conditions]))} " if ref && ref.options[:conditions]
1948
+ end
1949
+
1950
+ join
1951
+ end
1952
+
1953
+ protected
1954
+
1955
+ def aliased_table_name_for(name, suffix = nil)
1956
+ if !parent.table_joins.blank? && parent.table_joins.to_s.downcase =~ %r{join(\s+\w+)?\s+#{name.downcase}\son}
1957
+ @join_dependency.table_aliases[name] += 1
1958
+ end
1959
+
1960
+ unless @join_dependency.table_aliases[name].zero?
1961
+ # if the table name has been used, then use an alias
1962
+ name = active_record.connection.table_alias_for "#{pluralize(reflection.name)}_#{parent_table_name}#{suffix}"
1963
+ table_index = @join_dependency.table_aliases[name]
1964
+ @join_dependency.table_aliases[name] += 1
1965
+ name = name[0..active_record.connection.table_alias_length-3] + "_#{table_index+1}" if table_index > 0
1966
+ else
1967
+ @join_dependency.table_aliases[name] += 1
1968
+ end
1969
+
1970
+ name
1971
+ end
1972
+
1973
+ def pluralize(table_name)
1974
+ ActiveRecord::Base.pluralize_table_names ? table_name.to_s.pluralize : table_name
1975
+ end
1976
+
1977
+ def table_alias_for(table_name, table_alias)
1978
+ "#{reflection.active_record.connection.quote_table_name(table_name)} #{table_alias if table_name != table_alias}".strip
1979
+ end
1980
+
1981
+ def table_name_and_alias
1982
+ table_alias_for table_name, @aliased_table_name
1983
+ end
1984
+
1985
+ def interpolate_sql(sql)
1986
+ instance_eval("%@#{sql.gsub('@', '\@')}@")
1987
+ end
1988
+
1989
+ private
1990
+ def join_type
1991
+ "LEFT OUTER JOIN"
1992
+ end
1993
+ end
1994
+ end
1995
+
1996
+ class InnerJoinDependency < JoinDependency # :nodoc:
1997
+ protected
1998
+ def build_join_association(reflection, parent)
1999
+ InnerJoinAssociation.new(reflection, self, parent)
2000
+ end
2001
+
2002
+ class InnerJoinAssociation < JoinAssociation
2003
+ private
2004
+ def join_type
2005
+ "INNER JOIN"
2006
+ end
2007
+ end
2008
+ end
2009
+
2010
+ end
2011
+ end
2012
+ end