actionpack 2.3.18 → 3.0.0.beta

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 (513) hide show
  1. data/CHANGELOG +15 -64
  2. data/README +39 -48
  3. data/lib/abstract_controller.rb +22 -0
  4. data/lib/abstract_controller/base.rb +191 -0
  5. data/lib/abstract_controller/callbacks.rb +113 -0
  6. data/lib/abstract_controller/collector.rb +30 -0
  7. data/lib/abstract_controller/compatibility.rb +18 -0
  8. data/lib/abstract_controller/helpers.rb +163 -0
  9. data/lib/abstract_controller/layouts.rb +413 -0
  10. data/lib/abstract_controller/localized_cache.rb +49 -0
  11. data/lib/abstract_controller/logger.rb +13 -0
  12. data/lib/abstract_controller/rendering.rb +238 -0
  13. data/lib/{action_controller → abstract_controller}/translation.rb +1 -1
  14. data/lib/action_controller.rb +68 -102
  15. data/lib/action_controller/base.rb +77 -1409
  16. data/lib/action_controller/caching.rb +58 -45
  17. data/lib/action_controller/caching/actions.rb +100 -114
  18. data/lib/action_controller/caching/fragments.rb +17 -19
  19. data/lib/action_controller/caching/pages.rb +12 -6
  20. data/lib/action_controller/caching/sweeping.rb +42 -0
  21. data/lib/action_controller/deprecated.rb +5 -0
  22. data/lib/action_controller/deprecated/dispatcher.rb +28 -0
  23. data/lib/action_controller/deprecated/integration_test.rb +2 -0
  24. data/lib/action_controller/deprecated/performance_test.rb +1 -0
  25. data/lib/action_controller/metal.rb +125 -0
  26. data/lib/action_controller/metal/compatibility.rb +141 -0
  27. data/lib/action_controller/metal/conditional_get.rb +86 -0
  28. data/lib/action_controller/metal/configuration.rb +28 -0
  29. data/lib/action_controller/metal/cookies.rb +17 -0
  30. data/lib/action_controller/metal/exceptions.rb +46 -0
  31. data/lib/action_controller/metal/flash.rb +28 -0
  32. data/lib/action_controller/metal/head.rb +33 -0
  33. data/lib/action_controller/metal/helpers.rb +116 -0
  34. data/lib/action_controller/metal/hide_actions.rb +50 -0
  35. data/lib/action_controller/{http_authentication.rb → metal/http_authentication.rb} +18 -15
  36. data/lib/action_controller/metal/instrumentation.rb +99 -0
  37. data/lib/action_controller/metal/mime_responds.rb +300 -0
  38. data/lib/action_controller/metal/rack_delegation.rb +35 -0
  39. data/lib/action_controller/metal/redirecting.rb +90 -0
  40. data/lib/action_controller/metal/renderers.rb +95 -0
  41. data/lib/action_controller/metal/rendering.rb +69 -0
  42. data/lib/action_controller/metal/request_forgery_protection.rb +115 -0
  43. data/lib/action_controller/metal/rescue.rb +13 -0
  44. data/lib/action_controller/metal/responder.rb +220 -0
  45. data/lib/action_controller/{session_management.rb → metal/session_management.rb} +5 -14
  46. data/lib/action_controller/{streaming.rb → metal/streaming.rb} +13 -12
  47. data/lib/action_controller/metal/testing.rb +42 -0
  48. data/lib/action_controller/metal/url_for.rb +157 -0
  49. data/lib/action_controller/{verification.rb → metal/verification.rb} +41 -41
  50. data/lib/action_controller/middleware.rb +38 -0
  51. data/lib/action_controller/polymorphic_routes.rb +20 -26
  52. data/lib/action_controller/railtie.rb +30 -0
  53. data/lib/action_controller/railties/subscriber.rb +63 -0
  54. data/lib/action_controller/record_identifier.rb +3 -16
  55. data/lib/action_controller/test_case.rb +156 -18
  56. data/lib/action_controller/url_rewriter.rb +47 -200
  57. data/lib/action_controller/vendor/html-scanner.rb +16 -12
  58. data/lib/action_controller/vendor/html-scanner/html/node.rb +1 -1
  59. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +12 -9
  60. data/lib/action_dispatch.rb +88 -0
  61. data/lib/action_dispatch/http/cache.rb +123 -0
  62. data/lib/action_dispatch/http/filter_parameters.rb +98 -0
  63. data/lib/{action_controller → action_dispatch/http}/headers.rb +8 -8
  64. data/lib/action_dispatch/http/mime_negotiation.rb +101 -0
  65. data/lib/{action_controller → action_dispatch/http}/mime_type.rb +30 -11
  66. data/lib/{action_controller → action_dispatch/http}/mime_types.rb +5 -3
  67. data/lib/action_dispatch/http/parameters.rb +49 -0
  68. data/lib/action_dispatch/http/request.rb +223 -0
  69. data/lib/action_dispatch/http/response.rb +209 -0
  70. data/lib/action_dispatch/http/upload.rb +48 -0
  71. data/lib/action_dispatch/http/url.rb +129 -0
  72. data/lib/action_dispatch/middleware/callbacks.rb +50 -0
  73. data/lib/action_dispatch/middleware/cascade.rb +29 -0
  74. data/lib/action_dispatch/middleware/cookies.rb +216 -0
  75. data/lib/{action_controller → action_dispatch/middleware}/flash.rb +51 -90
  76. data/lib/action_dispatch/middleware/head.rb +18 -0
  77. data/lib/action_dispatch/middleware/params_parser.rb +78 -0
  78. data/lib/action_dispatch/middleware/rescue.rb +26 -0
  79. data/lib/action_dispatch/middleware/session/abstract_store.rb +209 -0
  80. data/lib/{action_controller → action_dispatch/middleware}/session/cookie_store.rb +56 -60
  81. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +47 -0
  82. data/lib/action_dispatch/middleware/show_exceptions.rb +173 -0
  83. data/lib/{action_controller/middleware_stack.rb → action_dispatch/middleware/stack.rb} +23 -13
  84. data/lib/action_dispatch/middleware/static.rb +44 -0
  85. data/lib/{action_controller → action_dispatch/middleware}/templates/rescues/_request_and_response.erb +10 -3
  86. data/lib/{action_controller → action_dispatch/middleware}/templates/rescues/_trace.erb +4 -4
  87. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +10 -0
  88. data/lib/{action_controller → action_dispatch/middleware}/templates/rescues/layout.erb +2 -2
  89. data/lib/{action_controller → action_dispatch/middleware}/templates/rescues/missing_template.erb +0 -0
  90. data/lib/{action_controller → action_dispatch/middleware}/templates/rescues/routing_error.erb +0 -0
  91. data/lib/{action_controller → action_dispatch/middleware}/templates/rescues/template_error.erb +3 -3
  92. data/lib/{action_controller → action_dispatch/middleware}/templates/rescues/unknown_action.erb +0 -0
  93. data/lib/action_dispatch/railtie.rb +15 -0
  94. data/lib/action_dispatch/routing.rb +217 -0
  95. data/lib/action_dispatch/routing/deprecated_mapper.rb +877 -0
  96. data/lib/action_dispatch/routing/mapper.rb +649 -0
  97. data/lib/action_dispatch/routing/route.rb +55 -0
  98. data/lib/action_dispatch/routing/route_set.rb +445 -0
  99. data/lib/action_dispatch/testing/assertions.rb +21 -0
  100. data/lib/action_dispatch/testing/assertions/dom.rb +37 -0
  101. data/lib/{action_controller/assertions/model_assertions.rb → action_dispatch/testing/assertions/model.rb} +2 -4
  102. data/lib/action_dispatch/testing/assertions/response.rb +154 -0
  103. data/lib/{action_controller/assertions/routing_assertions.rb → action_dispatch/testing/assertions/routing.rb} +72 -34
  104. data/lib/{action_controller/assertions/selector_assertions.rb → action_dispatch/testing/assertions/selector.rb} +14 -11
  105. data/lib/{action_controller/assertions/tag_assertions.rb → action_dispatch/testing/assertions/tag.rb} +25 -14
  106. data/lib/{action_controller → action_dispatch/testing}/integration.rb +173 -406
  107. data/lib/action_dispatch/testing/performance_test.rb +17 -0
  108. data/lib/action_dispatch/testing/test_process.rb +42 -0
  109. data/lib/action_dispatch/testing/test_request.rb +83 -0
  110. data/lib/action_dispatch/testing/test_response.rb +136 -0
  111. data/lib/action_pack/version.rb +3 -3
  112. data/lib/action_view.rb +29 -26
  113. data/lib/action_view/base.rb +101 -148
  114. data/lib/action_view/context.rb +44 -0
  115. data/lib/action_view/helpers.rb +6 -4
  116. data/lib/action_view/helpers/{active_record_helper.rb → active_model_helper.rb} +63 -63
  117. data/lib/action_view/helpers/asset_tag_helper.rb +166 -31
  118. data/lib/action_view/helpers/cache_helper.rb +1 -1
  119. data/lib/action_view/helpers/capture_helper.rb +40 -8
  120. data/lib/action_view/helpers/csrf_helper.rb +2 -4
  121. data/lib/action_view/helpers/date_helper.rb +14 -15
  122. data/lib/action_view/helpers/form_helper.rb +121 -24
  123. data/lib/action_view/helpers/form_options_helper.rb +26 -25
  124. data/lib/action_view/helpers/form_tag_helper.rb +42 -33
  125. data/lib/action_view/helpers/javascript_helper.rb +1 -109
  126. data/lib/action_view/helpers/number_helper.rb +4 -1
  127. data/lib/action_view/helpers/prototype_helper.rb +75 -499
  128. data/lib/action_view/helpers/raw_output_helper.rb +1 -1
  129. data/lib/action_view/helpers/record_tag_helper.rb +3 -3
  130. data/lib/action_view/helpers/sanitize_helper.rb +3 -2
  131. data/lib/action_view/helpers/scriptaculous_helper.rb +89 -53
  132. data/lib/action_view/helpers/tag_helper.rb +12 -13
  133. data/lib/action_view/helpers/text_helper.rb +33 -38
  134. data/lib/action_view/helpers/translation_helper.rb +11 -35
  135. data/lib/action_view/helpers/url_helper.rb +140 -134
  136. data/lib/action_view/locale/en.yml +34 -28
  137. data/lib/action_view/paths.rb +27 -24
  138. data/lib/action_view/railtie.rb +17 -0
  139. data/lib/action_view/railties/subscriber.rb +24 -0
  140. data/lib/action_view/{partials.rb → render/partials.rb} +161 -51
  141. data/lib/action_view/render/rendering.rb +117 -0
  142. data/lib/action_view/template.rb +88 -217
  143. data/lib/action_view/template/error.rb +105 -0
  144. data/lib/action_view/template/handler.rb +41 -0
  145. data/lib/action_view/template/handlers.rb +54 -0
  146. data/lib/action_view/{template_handlers → template/handlers}/builder.rb +6 -6
  147. data/lib/action_view/template/handlers/erb.rb +58 -0
  148. data/lib/action_view/{template_handlers → template/handlers}/rjs.rb +8 -3
  149. data/lib/action_view/template/resolver.rb +164 -0
  150. data/lib/action_view/template/text.rb +40 -0
  151. data/lib/action_view/test_case.rb +18 -18
  152. metadata +165 -420
  153. data/RUNNING_UNIT_TESTS +0 -24
  154. data/Rakefile +0 -158
  155. data/install.rb +0 -30
  156. data/lib/action_controller/assertions/dom_assertions.rb +0 -55
  157. data/lib/action_controller/assertions/response_assertions.rb +0 -169
  158. data/lib/action_controller/benchmarking.rb +0 -107
  159. data/lib/action_controller/caching/sweeper.rb +0 -45
  160. data/lib/action_controller/cgi_ext.rb +0 -15
  161. data/lib/action_controller/cgi_ext/cookie.rb +0 -112
  162. data/lib/action_controller/cgi_ext/query_extension.rb +0 -22
  163. data/lib/action_controller/cgi_ext/stdinput.rb +0 -24
  164. data/lib/action_controller/cgi_process.rb +0 -77
  165. data/lib/action_controller/cookies.rb +0 -197
  166. data/lib/action_controller/dispatcher.rb +0 -133
  167. data/lib/action_controller/failsafe.rb +0 -87
  168. data/lib/action_controller/filters.rb +0 -680
  169. data/lib/action_controller/helpers.rb +0 -225
  170. data/lib/action_controller/layout.rb +0 -286
  171. data/lib/action_controller/middlewares.rb +0 -14
  172. data/lib/action_controller/mime_responds.rb +0 -193
  173. data/lib/action_controller/params_parser.rb +0 -77
  174. data/lib/action_controller/performance_test.rb +0 -15
  175. data/lib/action_controller/rack_lint_patch.rb +0 -36
  176. data/lib/action_controller/reloader.rb +0 -54
  177. data/lib/action_controller/request.rb +0 -518
  178. data/lib/action_controller/request_forgery_protection.rb +0 -116
  179. data/lib/action_controller/rescue.rb +0 -183
  180. data/lib/action_controller/resources.rb +0 -682
  181. data/lib/action_controller/response.rb +0 -237
  182. data/lib/action_controller/routing.rb +0 -388
  183. data/lib/action_controller/routing/builder.rb +0 -197
  184. data/lib/action_controller/routing/optimisations.rb +0 -130
  185. data/lib/action_controller/routing/recognition_optimisation.rb +0 -167
  186. data/lib/action_controller/routing/route.rb +0 -265
  187. data/lib/action_controller/routing/route_set.rb +0 -503
  188. data/lib/action_controller/routing/routing_ext.rb +0 -49
  189. data/lib/action_controller/routing/segments.rb +0 -343
  190. data/lib/action_controller/session/abstract_store.rb +0 -276
  191. data/lib/action_controller/session/mem_cache_store.rb +0 -60
  192. data/lib/action_controller/status_codes.rb +0 -88
  193. data/lib/action_controller/string_coercion.rb +0 -29
  194. data/lib/action_controller/templates/rescues/diagnostics.erb +0 -11
  195. data/lib/action_controller/test_process.rb +0 -580
  196. data/lib/action_controller/uploaded_file.rb +0 -44
  197. data/lib/action_view/helpers/benchmark_helper.rb +0 -54
  198. data/lib/action_view/inline_template.rb +0 -19
  199. data/lib/action_view/reloadable_template.rb +0 -117
  200. data/lib/action_view/renderable.rb +0 -109
  201. data/lib/action_view/renderable_partial.rb +0 -53
  202. data/lib/action_view/template_error.rb +0 -99
  203. data/lib/action_view/template_handler.rb +0 -34
  204. data/lib/action_view/template_handlers.rb +0 -48
  205. data/lib/action_view/template_handlers/erb.rb +0 -25
  206. data/lib/actionpack.rb +0 -2
  207. data/test/abstract_unit.rb +0 -78
  208. data/test/active_record_unit.rb +0 -104
  209. data/test/activerecord/active_record_store_test.rb +0 -221
  210. data/test/activerecord/render_partial_with_record_identification_test.rb +0 -188
  211. data/test/adv_attr_test.rb +0 -20
  212. data/test/controller/action_pack_assertions_test.rb +0 -545
  213. data/test/controller/addresses_render_test.rb +0 -37
  214. data/test/controller/assert_select_test.rb +0 -735
  215. data/test/controller/base_test.rb +0 -217
  216. data/test/controller/benchmark_test.rb +0 -32
  217. data/test/controller/caching_test.rb +0 -743
  218. data/test/controller/capture_test.rb +0 -66
  219. data/test/controller/content_type_test.rb +0 -178
  220. data/test/controller/controller_fixtures/app/controllers/admin/user_controller.rb +0 -0
  221. data/test/controller/controller_fixtures/app/controllers/user_controller.rb +0 -0
  222. data/test/controller/controller_fixtures/vendor/plugins/bad_plugin/lib/plugin_controller.rb +0 -0
  223. data/test/controller/cookie_test.rb +0 -208
  224. data/test/controller/deprecation/deprecated_base_methods_test.rb +0 -32
  225. data/test/controller/dispatcher_test.rb +0 -144
  226. data/test/controller/dom_assertions_test.rb +0 -53
  227. data/test/controller/failsafe_test.rb +0 -60
  228. data/test/controller/fake_controllers.rb +0 -33
  229. data/test/controller/fake_models.rb +0 -19
  230. data/test/controller/filter_params_test.rb +0 -52
  231. data/test/controller/filters_test.rb +0 -885
  232. data/test/controller/flash_test.rb +0 -174
  233. data/test/controller/header_test.rb +0 -14
  234. data/test/controller/helper_test.rb +0 -224
  235. data/test/controller/html-scanner/cdata_node_test.rb +0 -15
  236. data/test/controller/html-scanner/document_test.rb +0 -148
  237. data/test/controller/html-scanner/node_test.rb +0 -89
  238. data/test/controller/html-scanner/sanitizer_test.rb +0 -300
  239. data/test/controller/html-scanner/tag_node_test.rb +0 -238
  240. data/test/controller/html-scanner/text_node_test.rb +0 -50
  241. data/test/controller/html-scanner/tokenizer_test.rb +0 -131
  242. data/test/controller/http_basic_authentication_test.rb +0 -113
  243. data/test/controller/http_digest_authentication_test.rb +0 -254
  244. data/test/controller/integration_test.rb +0 -526
  245. data/test/controller/layout_test.rb +0 -215
  246. data/test/controller/localized_templates_test.rb +0 -24
  247. data/test/controller/logging_test.rb +0 -46
  248. data/test/controller/middleware_stack_test.rb +0 -90
  249. data/test/controller/mime_responds_test.rb +0 -536
  250. data/test/controller/mime_type_test.rb +0 -93
  251. data/test/controller/output_escaping_test.rb +0 -19
  252. data/test/controller/polymorphic_routes_test.rb +0 -297
  253. data/test/controller/rack_test.rb +0 -308
  254. data/test/controller/record_identifier_test.rb +0 -139
  255. data/test/controller/redirect_test.rb +0 -285
  256. data/test/controller/reloader_test.rb +0 -125
  257. data/test/controller/render_test.rb +0 -1783
  258. data/test/controller/request/json_params_parsing_test.rb +0 -65
  259. data/test/controller/request/multipart_params_parsing_test.rb +0 -177
  260. data/test/controller/request/query_string_parsing_test.rb +0 -129
  261. data/test/controller/request/test_request_test.rb +0 -35
  262. data/test/controller/request/url_encoded_params_parsing_test.rb +0 -146
  263. data/test/controller/request/xml_params_parsing_test.rb +0 -103
  264. data/test/controller/request_forgery_protection_test.rb +0 -233
  265. data/test/controller/request_test.rb +0 -398
  266. data/test/controller/rescue_test.rb +0 -541
  267. data/test/controller/resources_test.rb +0 -1393
  268. data/test/controller/routing_test.rb +0 -2592
  269. data/test/controller/selector_test.rb +0 -628
  270. data/test/controller/send_file_test.rb +0 -171
  271. data/test/controller/session/abstract_store_test.rb +0 -64
  272. data/test/controller/session/cookie_store_test.rb +0 -354
  273. data/test/controller/session/mem_cache_store_test.rb +0 -187
  274. data/test/controller/session/test_session_test.rb +0 -58
  275. data/test/controller/test_test.rb +0 -700
  276. data/test/controller/translation_test.rb +0 -26
  277. data/test/controller/url_rewriter_test.rb +0 -395
  278. data/test/controller/verification_test.rb +0 -270
  279. data/test/controller/view_paths_test.rb +0 -141
  280. data/test/controller/webservice_test.rb +0 -273
  281. data/test/fixtures/_top_level_partial.html.erb +0 -1
  282. data/test/fixtures/_top_level_partial_only.erb +0 -1
  283. data/test/fixtures/addresses/list.erb +0 -1
  284. data/test/fixtures/alternate_helpers/foo_helper.rb +0 -3
  285. data/test/fixtures/bad_customers/_bad_customer.html.erb +0 -1
  286. data/test/fixtures/companies.yml +0 -24
  287. data/test/fixtures/company.rb +0 -10
  288. data/test/fixtures/content_type/render_default_content_types_for_respond_to.rhtml +0 -1
  289. data/test/fixtures/content_type/render_default_for_rhtml.rhtml +0 -1
  290. data/test/fixtures/content_type/render_default_for_rjs.rjs +0 -1
  291. data/test/fixtures/content_type/render_default_for_rxml.rxml +0 -1
  292. data/test/fixtures/customers/_customer.html.erb +0 -1
  293. data/test/fixtures/db_definitions/sqlite.sql +0 -49
  294. data/test/fixtures/developer.rb +0 -9
  295. data/test/fixtures/developers.yml +0 -21
  296. data/test/fixtures/developers/_developer.erb +0 -1
  297. data/test/fixtures/developers_projects.yml +0 -13
  298. data/test/fixtures/failsafe/500.html +0 -1
  299. data/test/fixtures/fun/games/_game.erb +0 -1
  300. data/test/fixtures/fun/games/hello_world.erb +0 -1
  301. data/test/fixtures/fun/serious/games/_game.erb +0 -1
  302. data/test/fixtures/functional_caching/_partial.erb +0 -3
  303. data/test/fixtures/functional_caching/formatted_fragment_cached.html.erb +0 -3
  304. data/test/fixtures/functional_caching/formatted_fragment_cached.js.rjs +0 -6
  305. data/test/fixtures/functional_caching/formatted_fragment_cached.xml.builder +0 -5
  306. data/test/fixtures/functional_caching/fragment_cached.html.erb +0 -2
  307. data/test/fixtures/functional_caching/html_fragment_cached_with_partial.html.erb +0 -1
  308. data/test/fixtures/functional_caching/inline_fragment_cached.html.erb +0 -2
  309. data/test/fixtures/functional_caching/js_fragment_cached_with_partial.js.rjs +0 -1
  310. data/test/fixtures/good_customers/_good_customer.html.erb +0 -1
  311. data/test/fixtures/helpers/abc_helper.rb +0 -5
  312. data/test/fixtures/helpers/fun/games_helper.rb +0 -3
  313. data/test/fixtures/helpers/fun/pdf_helper.rb +0 -3
  314. data/test/fixtures/layout_tests/abs_path_layout.rhtml +0 -1
  315. data/test/fixtures/layout_tests/alt/hello.rhtml +0 -1
  316. data/test/fixtures/layout_tests/alt/layouts/alt.rhtml +0 -0
  317. data/test/fixtures/layout_tests/layouts/controller_name_space/nested.rhtml +0 -1
  318. data/test/fixtures/layout_tests/layouts/item.rhtml +0 -1
  319. data/test/fixtures/layout_tests/layouts/layout_test.rhtml +0 -1
  320. data/test/fixtures/layout_tests/layouts/multiple_extensions.html.erb +0 -1
  321. data/test/fixtures/layout_tests/layouts/third_party_template_library.mab +0 -1
  322. data/test/fixtures/layout_tests/views/hello.rhtml +0 -1
  323. data/test/fixtures/layouts/_column.html.erb +0 -2
  324. data/test/fixtures/layouts/block_with_layout.erb +0 -3
  325. data/test/fixtures/layouts/builder.builder +0 -3
  326. data/test/fixtures/layouts/default_html.html.erb +0 -1
  327. data/test/fixtures/layouts/partial_with_layout.erb +0 -3
  328. data/test/fixtures/layouts/standard.erb +0 -1
  329. data/test/fixtures/layouts/talk_from_action.erb +0 -2
  330. data/test/fixtures/layouts/xhr.html.erb +0 -2
  331. data/test/fixtures/layouts/yield.erb +0 -2
  332. data/test/fixtures/localized/hello_world.de.html +0 -1
  333. data/test/fixtures/localized/hello_world.en.html +0 -1
  334. data/test/fixtures/mascot.rb +0 -3
  335. data/test/fixtures/mascots.yml +0 -4
  336. data/test/fixtures/mascots/_mascot.html.erb +0 -1
  337. data/test/fixtures/multipart/binary_file +0 -0
  338. data/test/fixtures/multipart/boundary_problem_file +0 -10
  339. data/test/fixtures/multipart/bracketed_param +0 -5
  340. data/test/fixtures/multipart/empty +0 -10
  341. data/test/fixtures/multipart/hello.txt +0 -1
  342. data/test/fixtures/multipart/large_text_file +0 -10
  343. data/test/fixtures/multipart/mixed_files +0 -0
  344. data/test/fixtures/multipart/mona_lisa.jpg +0 -0
  345. data/test/fixtures/multipart/none +0 -9
  346. data/test/fixtures/multipart/single_parameter +0 -5
  347. data/test/fixtures/multipart/text_file +0 -10
  348. data/test/fixtures/override/test/hello_world.erb +0 -1
  349. data/test/fixtures/override2/layouts/test/sub.erb +0 -1
  350. data/test/fixtures/post_test/layouts/post.html.erb +0 -1
  351. data/test/fixtures/post_test/layouts/super_post.iphone.erb +0 -1
  352. data/test/fixtures/post_test/post/index.html.erb +0 -1
  353. data/test/fixtures/post_test/post/index.iphone.erb +0 -1
  354. data/test/fixtures/post_test/super_post/index.html.erb +0 -1
  355. data/test/fixtures/post_test/super_post/index.iphone.erb +0 -1
  356. data/test/fixtures/project.rb +0 -3
  357. data/test/fixtures/projects.yml +0 -7
  358. data/test/fixtures/projects/_project.erb +0 -1
  359. data/test/fixtures/public/404.html +0 -1
  360. data/test/fixtures/public/500.da.html +0 -1
  361. data/test/fixtures/public/500.html +0 -1
  362. data/test/fixtures/public/absolute/test.css +0 -23
  363. data/test/fixtures/public/absolute/test.js +0 -63
  364. data/test/fixtures/public/images/rails.png +0 -0
  365. data/test/fixtures/public/javascripts/application.js +0 -1
  366. data/test/fixtures/public/javascripts/bank.js +0 -1
  367. data/test/fixtures/public/javascripts/controls.js +0 -1
  368. data/test/fixtures/public/javascripts/dragdrop.js +0 -1
  369. data/test/fixtures/public/javascripts/effects.js +0 -1
  370. data/test/fixtures/public/javascripts/prototype.js +0 -1
  371. data/test/fixtures/public/javascripts/robber.js +0 -1
  372. data/test/fixtures/public/javascripts/subdir/subdir.js +0 -1
  373. data/test/fixtures/public/javascripts/version.1.0.js +0 -1
  374. data/test/fixtures/public/stylesheets/bank.css +0 -1
  375. data/test/fixtures/public/stylesheets/robber.css +0 -1
  376. data/test/fixtures/public/stylesheets/subdir/subdir.css +0 -1
  377. data/test/fixtures/public/stylesheets/version.1.0.css +0 -1
  378. data/test/fixtures/quiz/questions/_question.html.erb +0 -1
  379. data/test/fixtures/replies.yml +0 -15
  380. data/test/fixtures/replies/_reply.erb +0 -1
  381. data/test/fixtures/reply.rb +0 -7
  382. data/test/fixtures/respond_to/all_types_with_layout.html.erb +0 -1
  383. data/test/fixtures/respond_to/all_types_with_layout.js.rjs +0 -1
  384. data/test/fixtures/respond_to/custom_constant_handling_without_block.mobile.erb +0 -1
  385. data/test/fixtures/respond_to/iphone_with_html_response_type.html.erb +0 -1
  386. data/test/fixtures/respond_to/iphone_with_html_response_type.iphone.erb +0 -1
  387. data/test/fixtures/respond_to/layouts/missing.html.erb +0 -1
  388. data/test/fixtures/respond_to/layouts/standard.html.erb +0 -1
  389. data/test/fixtures/respond_to/layouts/standard.iphone.erb +0 -1
  390. data/test/fixtures/respond_to/using_defaults.html.erb +0 -1
  391. data/test/fixtures/respond_to/using_defaults.js.rjs +0 -1
  392. data/test/fixtures/respond_to/using_defaults.xml.builder +0 -1
  393. data/test/fixtures/respond_to/using_defaults_with_type_list.html.erb +0 -1
  394. data/test/fixtures/respond_to/using_defaults_with_type_list.js.rjs +0 -1
  395. data/test/fixtures/respond_to/using_defaults_with_type_list.xml.builder +0 -1
  396. data/test/fixtures/scope/test/modgreet.erb +0 -1
  397. data/test/fixtures/session_autoload_test/session_autoload_test/foo.rb +0 -10
  398. data/test/fixtures/shared.html.erb +0 -1
  399. data/test/fixtures/symlink_parent/symlinked_layout.erb +0 -5
  400. data/test/fixtures/test/_counter.html.erb +0 -1
  401. data/test/fixtures/test/_customer.erb +0 -1
  402. data/test/fixtures/test/_customer_counter.erb +0 -1
  403. data/test/fixtures/test/_customer_counter_with_as.erb +0 -1
  404. data/test/fixtures/test/_customer_greeting.erb +0 -1
  405. data/test/fixtures/test/_customer_with_var.erb +0 -1
  406. data/test/fixtures/test/_form.erb +0 -1
  407. data/test/fixtures/test/_from_helper.erb +0 -1
  408. data/test/fixtures/test/_hash_greeting.erb +0 -1
  409. data/test/fixtures/test/_hash_object.erb +0 -2
  410. data/test/fixtures/test/_hello.builder +0 -1
  411. data/test/fixtures/test/_labelling_form.erb +0 -1
  412. data/test/fixtures/test/_layout_for_block_with_args.html.erb +0 -3
  413. data/test/fixtures/test/_layout_for_partial.html.erb +0 -3
  414. data/test/fixtures/test/_local_inspector.html.erb +0 -1
  415. data/test/fixtures/test/_one.html.erb +0 -1
  416. data/test/fixtures/test/_partial.erb +0 -1
  417. data/test/fixtures/test/_partial.html.erb +0 -1
  418. data/test/fixtures/test/_partial.js.erb +0 -1
  419. data/test/fixtures/test/_partial_for_use_in_layout.html.erb +0 -1
  420. data/test/fixtures/test/_partial_only.erb +0 -1
  421. data/test/fixtures/test/_partial_with_only_html_version.html.erb +0 -1
  422. data/test/fixtures/test/_person.erb +0 -2
  423. data/test/fixtures/test/_raise.html.erb +0 -1
  424. data/test/fixtures/test/_two.html.erb +0 -1
  425. data/test/fixtures/test/_utf8_partial.html.erb +0 -1
  426. data/test/fixtures/test/_utf8_partial_magic.html.erb +0 -2
  427. data/test/fixtures/test/action_talk_to_layout.erb +0 -2
  428. data/test/fixtures/test/array_translation.erb +0 -1
  429. data/test/fixtures/test/calling_partial_with_layout.html.erb +0 -1
  430. data/test/fixtures/test/capturing.erb +0 -4
  431. data/test/fixtures/test/content_for.erb +0 -2
  432. data/test/fixtures/test/content_for_concatenated.erb +0 -3
  433. data/test/fixtures/test/content_for_with_parameter.erb +0 -2
  434. data/test/fixtures/test/delete_with_js.rjs +0 -2
  435. data/test/fixtures/test/dont_pick_me +0 -1
  436. data/test/fixtures/test/dot.directory/render_file_with_ivar.erb +0 -1
  437. data/test/fixtures/test/enum_rjs_test.rjs +0 -6
  438. data/test/fixtures/test/formatted_html_erb.html.erb +0 -1
  439. data/test/fixtures/test/formatted_xml_erb.builder +0 -1
  440. data/test/fixtures/test/formatted_xml_erb.html.erb +0 -1
  441. data/test/fixtures/test/formatted_xml_erb.xml.erb +0 -1
  442. data/test/fixtures/test/greeting.erb +0 -1
  443. data/test/fixtures/test/greeting.js.rjs +0 -1
  444. data/test/fixtures/test/hello.builder +0 -4
  445. data/test/fixtures/test/hello_world.da.html.erb +0 -1
  446. data/test/fixtures/test/hello_world.erb +0 -1
  447. data/test/fixtures/test/hello_world.erb~ +0 -1
  448. data/test/fixtures/test/hello_world.pt-BR.html.erb +0 -1
  449. data/test/fixtures/test/hello_world_container.builder +0 -3
  450. data/test/fixtures/test/hello_world_from_rxml.builder +0 -4
  451. data/test/fixtures/test/hello_world_with_layout_false.erb +0 -1
  452. data/test/fixtures/test/hello_xml_world.builder +0 -11
  453. data/test/fixtures/test/hyphen-ated.erb +0 -1
  454. data/test/fixtures/test/implicit_content_type.atom.builder +0 -2
  455. data/test/fixtures/test/list.erb +0 -1
  456. data/test/fixtures/test/malformed/malformed.en.html.erb~ +0 -1
  457. data/test/fixtures/test/malformed/malformed.erb~ +0 -1
  458. data/test/fixtures/test/malformed/malformed.html.erb~ +0 -1
  459. data/test/fixtures/test/nested_layout.erb +0 -3
  460. data/test/fixtures/test/non_erb_block_content_for.builder +0 -4
  461. data/test/fixtures/test/potential_conflicts.erb +0 -4
  462. data/test/fixtures/test/render_explicit_html_template.js.rjs +0 -1
  463. data/test/fixtures/test/render_file_from_template.html.erb +0 -1
  464. data/test/fixtures/test/render_file_with_ivar.erb +0 -1
  465. data/test/fixtures/test/render_file_with_locals.erb +0 -1
  466. data/test/fixtures/test/render_implicit_html_template.js.rjs +0 -1
  467. data/test/fixtures/test/render_implicit_html_template_from_xhr_request.da.html.erb +0 -1
  468. data/test/fixtures/test/render_implicit_html_template_from_xhr_request.html.erb +0 -1
  469. data/test/fixtures/test/render_implicit_js_template_without_layout.js.erb +0 -1
  470. data/test/fixtures/test/render_to_string_test.erb +0 -1
  471. data/test/fixtures/test/scoped_array_translation.erb +0 -1
  472. data/test/fixtures/test/sub_template_raise.html.erb +0 -1
  473. data/test/fixtures/test/template.erb +0 -1
  474. data/test/fixtures/test/translation.erb +0 -1
  475. data/test/fixtures/test/update_element_with_capture.erb +0 -9
  476. data/test/fixtures/test/using_layout_around_block.html.erb +0 -1
  477. data/test/fixtures/test/using_layout_around_block_with_args.html.erb +0 -1
  478. data/test/fixtures/test/utf8.html.erb +0 -4
  479. data/test/fixtures/test/utf8_magic.html.erb +0 -5
  480. data/test/fixtures/test/utf8_magic_with_bare_partial.html.erb +0 -5
  481. data/test/fixtures/topic.rb +0 -3
  482. data/test/fixtures/topics.yml +0 -22
  483. data/test/fixtures/topics/_topic.html.erb +0 -1
  484. data/test/template/active_record_helper_i18n_test.rb +0 -51
  485. data/test/template/active_record_helper_test.rb +0 -302
  486. data/test/template/asset_tag_helper_test.rb +0 -770
  487. data/test/template/atom_feed_helper_test.rb +0 -315
  488. data/test/template/benchmark_helper_test.rb +0 -86
  489. data/test/template/compiled_templates_test.rb +0 -204
  490. data/test/template/date_helper_i18n_test.rb +0 -121
  491. data/test/template/date_helper_test.rb +0 -2603
  492. data/test/template/erb_util_test.rb +0 -36
  493. data/test/template/form_helper_test.rb +0 -1447
  494. data/test/template/form_options_helper_i18n_test.rb +0 -27
  495. data/test/template/form_options_helper_test.rb +0 -811
  496. data/test/template/form_tag_helper_test.rb +0 -356
  497. data/test/template/javascript_helper_test.rb +0 -106
  498. data/test/template/number_helper_i18n_test.rb +0 -69
  499. data/test/template/number_helper_test.rb +0 -132
  500. data/test/template/prototype_helper_test.rb +0 -639
  501. data/test/template/raw_output_helper_test.rb +0 -21
  502. data/test/template/record_tag_helper_test.rb +0 -58
  503. data/test/template/render_test.rb +0 -329
  504. data/test/template/sanitize_helper_test.rb +0 -57
  505. data/test/template/scriptaculous_helper_test.rb +0 -90
  506. data/test/template/tag_helper_test.rb +0 -98
  507. data/test/template/template_test.rb +0 -32
  508. data/test/template/test_test.rb +0 -54
  509. data/test/template/text_helper_test.rb +0 -601
  510. data/test/template/translation_helper_test.rb +0 -95
  511. data/test/template/url_helper_test.rb +0 -641
  512. data/test/testing_sandbox.rb +0 -15
  513. data/test/view/test_case_test.rb +0 -176
@@ -0,0 +1,44 @@
1
+ require 'rack/utils'
2
+
3
+ module ActionDispatch
4
+ class Static
5
+ FILE_METHODS = %w(GET HEAD).freeze
6
+
7
+ def initialize(app, root)
8
+ @app = app
9
+ @file_server = ::Rack::File.new(root)
10
+ end
11
+
12
+ def call(env)
13
+ path = env['PATH_INFO'].chomp('/')
14
+ method = env['REQUEST_METHOD']
15
+
16
+ if FILE_METHODS.include?(method)
17
+ if file_exist?(path)
18
+ return @file_server.call(env)
19
+ else
20
+ cached_path = directory_exist?(path) ? "#{path}/index" : path
21
+ cached_path += ::ActionController::Base.page_cache_extension
22
+
23
+ if file_exist?(cached_path)
24
+ env['PATH_INFO'] = cached_path
25
+ return @file_server.call(env)
26
+ end
27
+ end
28
+ end
29
+
30
+ @app.call(env)
31
+ end
32
+
33
+ private
34
+ def file_exist?(path)
35
+ full_path = File.join(@file_server.root, ::Rack::Utils.unescape(path))
36
+ File.file?(full_path) && File.readable?(full_path)
37
+ end
38
+
39
+ def directory_exist?(path)
40
+ full_path = File.join(@file_server.root, ::Rack::Utils.unescape(path))
41
+ File.directory?(full_path) && File.readable?(full_path)
42
+ end
43
+ end
44
+ end
@@ -6,19 +6,26 @@
6
6
  <% end %>
7
7
 
8
8
  <%
9
- clean_params = request.parameters.clone
9
+ clean_params = @request.parameters.clone
10
10
  clean_params.delete("action")
11
11
  clean_params.delete("controller")
12
12
 
13
13
  request_dump = clean_params.empty? ? 'None' : clean_params.inspect.gsub(',', ",\n")
14
+
15
+ def debug_hash(hash)
16
+ hash.sort_by { |k, v| k.to_s }.map { |k, v| "#{k}: #{v.inspect}" }.join("\n")
17
+ end
14
18
  %>
15
19
 
16
20
  <h2 style="margin-top: 30px">Request</h2>
17
21
  <p><b>Parameters</b>: <pre><%=h request_dump %></pre></p>
18
22
 
19
23
  <p><a href="#" onclick="document.getElementById('session_dump').style.display='block'; return false;">Show session dump</a></p>
20
- <div id="session_dump" style="display:none"><%= debug(request.session.instance_variable_get("@data")) %></div>
24
+ <div id="session_dump" style="display:none"><pre><%= debug_hash @request.session %></pre></div>
25
+
26
+ <p><a href="#" onclick="document.getElementById('env_dump').style.display='block'; return false;">Show env dump</a></p>
27
+ <div id="env_dump" style="display:none"><pre><%= debug_hash @request.env %></pre></div>
21
28
 
22
29
 
23
30
  <h2 style="margin-top: 30px">Response</h2>
24
- <p><b>Headers</b>: <pre><%=h response ? response.headers.inspect.gsub(',', ",\n") : 'None' %></pre></p>
31
+ <p><b>Headers</b>: <pre><%=h @response ? @response.headers.inspect.gsub(',', ",\n") : 'None' %></pre></p>
@@ -1,13 +1,13 @@
1
1
  <%
2
2
  traces = [
3
- ["Application Trace", @exception.application_backtrace],
4
- ["Framework Trace", @exception.framework_backtrace],
5
- ["Full Trace", @exception.clean_backtrace]
3
+ ["Application Trace", @application_trace],
4
+ ["Framework Trace", @framework_trace],
5
+ ["Full Trace", @full_trace]
6
6
  ]
7
7
  names = traces.collect {|name, trace| name}
8
8
  %>
9
9
 
10
- <p><code>RAILS_ROOT: <%= defined?(RAILS_ROOT) ? RAILS_ROOT : "unset" %></code></p>
10
+ <p><code>Rails.root: <%= defined?(Rails) && Rails.respond_to?(:root) ? Rails.root : "unset" %></code></p>
11
11
 
12
12
  <div id="traces">
13
13
  <% names.each do |name| %>
@@ -0,0 +1,10 @@
1
+ <h1>
2
+ <%=h @exception.class.to_s %>
3
+ <% if @request.parameters['controller'] %>
4
+ in <%=h @request.parameters['controller'].humanize %>Controller<% if @request.parameters['action'] %>#<%=h @request.parameters['action'] %><% end %>
5
+ <% end %>
6
+ </h1>
7
+ <pre><%=h @exception.message %></pre>
8
+
9
+ <%= render :file => "rescues/_trace.erb" %>
10
+ <%= render :file => "rescues/_request_and_response.erb" %>
@@ -23,7 +23,7 @@
23
23
  </head>
24
24
  <body>
25
25
 
26
- <%= @contents %>
26
+ <%= yield %>
27
27
 
28
28
  </body>
29
- </html>
29
+ </html>
@@ -1,6 +1,6 @@
1
1
  <h1>
2
2
  <%=h @exception.original_exception.class.to_s %> in
3
- <%=h request.parameters["controller"].capitalize if request.parameters["controller"]%>#<%=h request.parameters["action"] %>
3
+ <%=h @request.parameters["controller"].capitalize if @request.parameters["controller"]%>#<%=h @request.parameters["action"] %>
4
4
  </h1>
5
5
 
6
6
  <p>
@@ -15,7 +15,7 @@
15
15
 
16
16
  <% @real_exception = @exception
17
17
  @exception = @exception.original_exception || @exception %>
18
- <%= render :file => @rescues_path["rescues/_trace.erb"] %>
18
+ <%= render :file => "rescues/_trace.erb" %>
19
19
  <% @exception = @real_exception %>
20
20
 
21
- <%= render :file => @rescues_path["rescues/_request_and_response.erb"] %>
21
+ <%= render :file => "rescues/_request_and_response.erb" %>
@@ -0,0 +1,15 @@
1
+ require "action_dispatch"
2
+ require "rails"
3
+
4
+ module ActionDispatch
5
+ class Railtie < Rails::Railtie
6
+ railtie_name :action_dispatch
7
+
8
+ # Prepare dispatcher callbacks and run 'prepare' callbacks
9
+ initializer "action_dispatch.prepare_dispatcher" do |app|
10
+ # TODO: This used to say unless defined?(Dispatcher). Find out why and fix.
11
+ require 'rails/dispatcher'
12
+ ActionDispatch::Callbacks.to_prepare { app.routes_reloader.reload_if_changed }
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,217 @@
1
+ require 'active_support/core_ext/object/to_param'
2
+ require 'active_support/core_ext/regexp'
3
+
4
+ module ActionDispatch
5
+ # == Routing
6
+ #
7
+ # The routing module provides URL rewriting in native Ruby. It's a way to
8
+ # redirect incoming requests to controllers and actions. This replaces
9
+ # mod_rewrite rules. Best of all, Rails' Routing works with any web server.
10
+ # Routes are defined in <tt>config/routes.rb</tt>.
11
+ #
12
+ # Consider the following route, which you will find commented out at the
13
+ # bottom of your generated <tt>config/routes.rb</tt>:
14
+ #
15
+ # match ':controller(/:action(/:id(.:format)))'
16
+ #
17
+ # This route states that it expects requests to consist of a
18
+ # <tt>:controller</tt> followed optionally by an <tt>:action</tt> that in
19
+ # turn is followed optionally by an <tt>:id</tt>, which in turn is followed
20
+ # optionally by a <tt>:format</tt>
21
+ #
22
+ # Suppose you get an incoming request for <tt>/blog/edit/22</tt>, you'll end
23
+ # up with:
24
+ #
25
+ # params = { :controller => 'blog',
26
+ # :action => 'edit',
27
+ # :id => '22'
28
+ # }
29
+ #
30
+ # Think of creating routes as drawing a map for your requests. The map tells
31
+ # them where to go based on some predefined pattern:
32
+ #
33
+ # AppName::Applications.routes.draw do |map|
34
+ # Pattern 1 tells some request to go to one place
35
+ # Pattern 2 tell them to go to another
36
+ # ...
37
+ # end
38
+ #
39
+ # The following symbols are special:
40
+ #
41
+ # :controller maps to your controller name
42
+ # :action maps to an action with your controllers
43
+ #
44
+ # Other names simply map to a parameter as in the case of <tt>:id</tt>.
45
+ #
46
+ # == Named routes
47
+ #
48
+ # Routes can be named by passing an <tt>:as</tt> option,
49
+ # allowing for easy reference within your source as +name_of_route_url+
50
+ # for the full URL and +name_of_route_path+ for the URI path.
51
+ #
52
+ # Example:
53
+ #
54
+ # # In routes.rb
55
+ # match '/login' => 'accounts#login', :as => 'login'
56
+ #
57
+ # # With render, redirect_to, tests, etc.
58
+ # redirect_to login_url
59
+ #
60
+ # Arguments can be passed as well.
61
+ #
62
+ # redirect_to show_item_path(:id => 25)
63
+ #
64
+ # Use <tt>root</tt> as a shorthand to name a route for the root path "".
65
+ #
66
+ # # In routes.rb
67
+ # root :to => 'blogs#index'
68
+ #
69
+ # # would recognize http://www.example.com/ as
70
+ # params = { :controller => 'blogs', :action => 'index' }
71
+ #
72
+ # # and provide these named routes
73
+ # root_url # => 'http://www.example.com/'
74
+ # root_path # => ''
75
+ #
76
+ # Note: when using +controller+, the route is simply named after the
77
+ # method you call on the block parameter rather than map.
78
+ #
79
+ # # In routes.rb
80
+ # controller :blog do
81
+ # match 'blog/show' => :list
82
+ # match 'blog/delete' => :delete
83
+ # match 'blog/edit/:id' => :edit
84
+ # end
85
+ #
86
+ # # provides named routes for show, delete, and edit
87
+ # link_to @article.title, show_path(:id => @article.id)
88
+ #
89
+ # == Pretty URLs
90
+ #
91
+ # Routes can generate pretty URLs. For example:
92
+ #
93
+ # match '/articles/:year/:month/:day', :constraints => {
94
+ # :controller => 'articles',
95
+ # :action => 'find_by_date',
96
+ # :year => /\d{4}/,
97
+ # :month => /\d{1,2}/,
98
+ # :day => /\d{1,2}/
99
+ # }
100
+ #
101
+ # Using the route above, the URL "http://localhost:3000/articles/2005/11/06"
102
+ # maps to
103
+ #
104
+ # params = {:year => '2005', :month => '11', :day => '06'}
105
+ #
106
+ # == Regular Expressions and parameters
107
+ # You can specify a regular expression to define a format for a parameter.
108
+ #
109
+ # controller 'geocode' do
110
+ # match 'geocode/:postalcode' => :show', :constraints => {
111
+ # :postalcode => /\d{5}(-\d{4})?/
112
+ # }
113
+ #
114
+ # Constraints can include the 'ignorecase' and 'extended syntax' regular
115
+ # expression modifiers:
116
+ #
117
+ # controller 'geocode' do
118
+ # match 'geocode/:postalcode' => :show', :constraints => {
119
+ # :postalcode => /hx\d\d\s\d[a-z]{2}/i
120
+ # }
121
+ # end
122
+ #
123
+ # controller 'geocode' do
124
+ # match 'geocode/:postalcode' => :show', :constraints => {
125
+ # :postalcode => /# Postcode format
126
+ # \d{5} #Prefix
127
+ # (-\d{4})? #Suffix
128
+ # /x
129
+ # }
130
+ # end
131
+ #
132
+ # Using the multiline match modifier will raise an ArgumentError.
133
+ # Encoding regular expression modifiers are silently ignored. The
134
+ # match will always use the default encoding or ASCII.
135
+ #
136
+ # == HTTP Methods
137
+ #
138
+ # With conditions you can define restrictions on routes. Currently the only valid condition is <tt>:method</tt>.
139
+ #
140
+ # * <tt>:method</tt> - Allows you to specify which HTTP method(s) can access the route. Possible values are
141
+ # <tt>:post</tt>, <tt>:get</tt>, <tt>:put</tt>, <tt>:delete</tt> and <tt>:any</tt>. Use an array to specify more
142
+ # than one method, e.g. <tt>[ :get, :post ]</tt>. The default value is <tt>:any</tt>, <tt>:any</tt> means that any
143
+ # method can access the route.
144
+ #
145
+ # Example:
146
+ #
147
+ # get 'post/:id' => 'posts#show'
148
+ # post 'post/:id' => "posts#create_comment'
149
+ #
150
+ # Now, if you POST to <tt>/posts/:id</tt>, it will route to the <tt>create_comment</tt> action. A GET on the same
151
+ # URL will route to the <tt>show</tt> action.
152
+ #
153
+ # == Reloading routes
154
+ #
155
+ # You can reload routes if you feel you must:
156
+ #
157
+ # Rails::Application.reload_routes!
158
+ #
159
+ # This will clear all named routes and reload routes.rb if the file has been modified from
160
+ # last load. To absolutely force reloading, use <tt>reload!</tt>.
161
+ #
162
+ # == Testing Routes
163
+ #
164
+ # The two main methods for testing your routes:
165
+ #
166
+ # === +assert_routing+
167
+ #
168
+ # def test_movie_route_properly_splits
169
+ # opts = {:controller => "plugin", :action => "checkout", :id => "2"}
170
+ # assert_routing "plugin/checkout/2", opts
171
+ # end
172
+ #
173
+ # +assert_routing+ lets you test whether or not the route properly resolves into options.
174
+ #
175
+ # === +assert_recognizes+
176
+ #
177
+ # def test_route_has_options
178
+ # opts = {:controller => "plugin", :action => "show", :id => "12"}
179
+ # assert_recognizes opts, "/plugins/show/12"
180
+ # end
181
+ #
182
+ # Note the subtle difference between the two: +assert_routing+ tests that
183
+ # a URL fits options while +assert_recognizes+ tests that a URL
184
+ # breaks into parameters properly.
185
+ #
186
+ # In tests you can simply pass the URL or named route to +get+ or +post+.
187
+ #
188
+ # def send_to_jail
189
+ # get '/jail'
190
+ # assert_response :success
191
+ # assert_template "jail/front"
192
+ # end
193
+ #
194
+ # def goes_to_login
195
+ # get login_url
196
+ # #...
197
+ # end
198
+ #
199
+ # == View a list of all your routes
200
+ #
201
+ # Run <tt>rake routes</tt>.
202
+ #
203
+ module Routing
204
+ autoload :DeprecatedMapper, 'action_dispatch/routing/deprecated_mapper'
205
+ autoload :Mapper, 'action_dispatch/routing/mapper'
206
+ autoload :Route, 'action_dispatch/routing/route'
207
+ autoload :RouteSet, 'action_dispatch/routing/route_set'
208
+
209
+ SEPARATORS = %w( / . ? )
210
+ HTTP_METHODS = [:get, :head, :post, :put, :delete, :options]
211
+
212
+ # A helper module to hold URL related helpers.
213
+ module Helpers
214
+ include ActionController::PolymorphicRoutes
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,877 @@
1
+ module ActionDispatch
2
+ module Routing
3
+ # Mapper instances are used to build routes. The object passed to the draw
4
+ # block in config/routes.rb is a Mapper instance.
5
+ #
6
+ # Mapper instances have relatively few instance methods, in order to avoid
7
+ # clashes with named routes.
8
+ #
9
+ # == Overview
10
+ #
11
+ # ActionController::Resources are a way of defining RESTful \resources. A RESTful \resource, in basic terms,
12
+ # is something that can be pointed at and it will respond with a representation of the data requested.
13
+ # In real terms this could mean a user with a browser requests an HTML page, or that a desktop application
14
+ # requests XML data.
15
+ #
16
+ # RESTful design is based on the assumption that there are four generic verbs that a user of an
17
+ # application can request from a \resource (the noun).
18
+ #
19
+ # \Resources can be requested using four basic HTTP verbs (GET, POST, PUT, DELETE), the method used
20
+ # denotes the type of action that should take place.
21
+ #
22
+ # === The Different Methods and their Usage
23
+ #
24
+ # * GET - Requests for a \resource, no saving or editing of a \resource should occur in a GET request.
25
+ # * POST - Creation of \resources.
26
+ # * PUT - Editing of attributes on a \resource.
27
+ # * DELETE - Deletion of a \resource.
28
+ #
29
+ # === Examples
30
+ #
31
+ # # A GET request on the Posts resource is asking for all Posts
32
+ # GET /posts
33
+ #
34
+ # # A GET request on a single Post resource is asking for that particular Post
35
+ # GET /posts/1
36
+ #
37
+ # # A POST request on the Posts resource is asking for a Post to be created with the supplied details
38
+ # POST /posts # with => { :post => { :title => "My Whizzy New Post", :body => "I've got a brand new combine harvester" } }
39
+ #
40
+ # # A PUT request on a single Post resource is asking for a Post to be updated
41
+ # PUT /posts # with => { :id => 1, :post => { :title => "Changed Whizzy Title" } }
42
+ #
43
+ # # A DELETE request on a single Post resource is asking for it to be deleted
44
+ # DELETE /posts # with => { :id => 1 }
45
+ #
46
+ # By using the REST convention, users of our application can assume certain things about how the data
47
+ # is requested and how it is returned. Rails simplifies the routing part of RESTful design by
48
+ # supplying you with methods to create them in your routes.rb file.
49
+ #
50
+ # Read more about REST at http://en.wikipedia.org/wiki/Representational_State_Transfer
51
+ class DeprecatedMapper #:doc:
52
+ def initialize(set) #:nodoc:
53
+ @set = set
54
+ end
55
+
56
+ # Create an unnamed route with the provided +path+ and +options+. See
57
+ # ActionDispatch::Routing for an introduction to routes.
58
+ def connect(path, options = {})
59
+ options = options.dup
60
+
61
+ if conditions = options.delete(:conditions)
62
+ conditions = conditions.dup
63
+ method = [conditions.delete(:method)].flatten.compact
64
+ method.map! { |m|
65
+ m = m.to_s.upcase
66
+
67
+ if m == "HEAD"
68
+ raise ArgumentError, "HTTP method HEAD is invalid in route conditions. Rails processes HEAD requests the same as GETs, returning just the response headers"
69
+ end
70
+
71
+ unless HTTP_METHODS.include?(m.downcase.to_sym)
72
+ raise ArgumentError, "Invalid HTTP method specified in route conditions"
73
+ end
74
+
75
+ m
76
+ }
77
+
78
+ if method.length > 1
79
+ method = Regexp.union(*method)
80
+ elsif method.length == 1
81
+ method = method.first
82
+ else
83
+ method = nil
84
+ end
85
+ end
86
+
87
+ path_prefix = options.delete(:path_prefix)
88
+ name_prefix = options.delete(:name_prefix)
89
+ namespace = options.delete(:namespace)
90
+
91
+ name = options.delete(:_name)
92
+ name = "#{name_prefix}#{name}" if name_prefix
93
+
94
+ requirements = options.delete(:requirements) || {}
95
+ defaults = options.delete(:defaults) || {}
96
+ options.each do |k, v|
97
+ if v.is_a?(Regexp)
98
+ if value = options.delete(k)
99
+ requirements[k.to_sym] = value
100
+ end
101
+ else
102
+ value = options.delete(k)
103
+ defaults[k.to_sym] = value.is_a?(Symbol) ? value : value.to_param
104
+ end
105
+ end
106
+
107
+ requirements.each do |_, requirement|
108
+ if requirement.source =~ %r{\A(\\A|\^)|(\\Z|\\z|\$)\Z}
109
+ raise ArgumentError, "Regexp anchor characters are not allowed in routing requirements: #{requirement.inspect}"
110
+ end
111
+ if requirement.multiline?
112
+ raise ArgumentError, "Regexp multiline option not allowed in routing requirements: #{requirement.inspect}"
113
+ end
114
+ end
115
+
116
+ requirements[:controller] ||= @set.controller_constraints
117
+
118
+ if defaults[:controller]
119
+ defaults[:action] ||= 'index'
120
+ defaults[:controller] = defaults[:controller].to_s
121
+ defaults[:controller] = "#{namespace}#{defaults[:controller]}" if namespace
122
+ end
123
+
124
+ if defaults[:action]
125
+ defaults[:action] = defaults[:action].to_s
126
+ end
127
+
128
+ if path.is_a?(String)
129
+ path = "#{path_prefix}/#{path}" if path_prefix
130
+ path = path.gsub('.:format', '(.:format)')
131
+ path = optionalize_trailing_dynamic_segments(path, requirements, defaults)
132
+ glob = $1.to_sym if path =~ /\/\*(\w+)$/
133
+ path = ::Rack::Mount::Utils.normalize_path(path)
134
+
135
+ if glob && !defaults[glob].blank?
136
+ raise ActionController::RoutingError, "paths cannot have non-empty default values"
137
+ end
138
+ end
139
+
140
+ app = Routing::RouteSet::Dispatcher.new(:defaults => defaults, :glob => glob)
141
+
142
+ conditions = {}
143
+ conditions[:request_method] = method if method
144
+ conditions[:path_info] = path if path
145
+
146
+ @set.add_route(app, conditions, requirements, defaults, name)
147
+ end
148
+
149
+ def optionalize_trailing_dynamic_segments(path, requirements, defaults) #:nodoc:
150
+ path = (path =~ /^\//) ? path.dup : "/#{path}"
151
+ optional, segments = true, []
152
+
153
+ required_segments = requirements.keys
154
+ required_segments -= defaults.keys.compact
155
+
156
+ old_segments = path.split('/')
157
+ old_segments.shift
158
+ length = old_segments.length
159
+
160
+ old_segments.reverse.each_with_index do |segment, index|
161
+ required_segments.each do |required|
162
+ if segment =~ /#{required}/
163
+ optional = false
164
+ break
165
+ end
166
+ end
167
+
168
+ if optional
169
+ if segment == ":id" && segments.include?(":action")
170
+ optional = false
171
+ elsif segment == ":controller" || segment == ":action" || segment == ":id"
172
+ # Ignore
173
+ elsif !(segment =~ /^:\w+$/) &&
174
+ !(segment =~ /^:\w+\(\.:format\)$/)
175
+ optional = false
176
+ elsif segment =~ /^:(\w+)$/
177
+ if defaults.has_key?($1.to_sym)
178
+ defaults.delete($1.to_sym) if defaults[$1.to_sym].nil?
179
+ else
180
+ optional = false
181
+ end
182
+ end
183
+ end
184
+
185
+ if optional && index < length - 1
186
+ segments.unshift('(/', segment)
187
+ segments.push(')')
188
+ elsif optional
189
+ segments.unshift('/(', segment)
190
+ segments.push(')')
191
+ else
192
+ segments.unshift('/', segment)
193
+ end
194
+ end
195
+
196
+ segments.join
197
+ end
198
+ private :optionalize_trailing_dynamic_segments
199
+
200
+ # Creates a named route called "root" for matching the root level request.
201
+ def root(options = {})
202
+ if options.is_a?(Symbol)
203
+ if source_route = @set.named_routes.routes[options]
204
+ options = source_route.defaults.merge({ :conditions => source_route.conditions })
205
+ end
206
+ end
207
+ named_route("root", '', options)
208
+ end
209
+
210
+ def named_route(name, path, options = {}) #:nodoc:
211
+ options[:_name] = name
212
+ connect(path, options)
213
+ end
214
+
215
+ # Enables the use of resources in a module by setting the name_prefix, path_prefix, and namespace for the model.
216
+ # Example:
217
+ #
218
+ # map.namespace(:admin) do |admin|
219
+ # admin.resources :products,
220
+ # :has_many => [ :tags, :images, :variants ]
221
+ # end
222
+ #
223
+ # This will create +admin_products_url+ pointing to "admin/products", which will look for an Admin::ProductsController.
224
+ # It'll also create +admin_product_tags_url+ pointing to "admin/products/#{product_id}/tags", which will look for
225
+ # Admin::TagsController.
226
+ def namespace(name, options = {}, &block)
227
+ if options[:namespace]
228
+ with_options({:path_prefix => "#{options.delete(:path_prefix)}/#{name}", :name_prefix => "#{options.delete(:name_prefix)}#{name}_", :namespace => "#{options.delete(:namespace)}#{name}/" }.merge(options), &block)
229
+ else
230
+ with_options({:path_prefix => name, :name_prefix => "#{name}_", :namespace => "#{name}/" }.merge(options), &block)
231
+ end
232
+ end
233
+
234
+ def method_missing(route_name, *args, &proc) #:nodoc:
235
+ super unless args.length >= 1 && proc.nil?
236
+ named_route(route_name, *args)
237
+ end
238
+
239
+ INHERITABLE_OPTIONS = :namespace, :shallow
240
+
241
+ class Resource #:nodoc:
242
+ DEFAULT_ACTIONS = :index, :create, :new, :edit, :show, :update, :destroy
243
+
244
+ attr_reader :collection_methods, :member_methods, :new_methods
245
+ attr_reader :path_prefix, :name_prefix, :path_segment
246
+ attr_reader :plural, :singular
247
+ attr_reader :options
248
+
249
+ def initialize(entities, options)
250
+ @plural ||= entities
251
+ @singular ||= options[:singular] || plural.to_s.singularize
252
+ @path_segment = options.delete(:as) || @plural
253
+
254
+ @options = options
255
+
256
+ arrange_actions
257
+ add_default_actions
258
+ set_allowed_actions
259
+ set_prefixes
260
+ end
261
+
262
+ def controller
263
+ @controller ||= "#{options[:namespace]}#{(options[:controller] || plural).to_s}"
264
+ end
265
+
266
+ def requirements(with_id = false)
267
+ @requirements ||= @options[:requirements] || {}
268
+ @id_requirement ||= { :id => @requirements.delete(:id) || /[^#{Routing::SEPARATORS.join}]+/ }
269
+
270
+ with_id ? @requirements.merge(@id_requirement) : @requirements
271
+ end
272
+
273
+ def conditions
274
+ @conditions ||= @options[:conditions] || {}
275
+ end
276
+
277
+ def path
278
+ @path ||= "#{path_prefix}/#{path_segment}"
279
+ end
280
+
281
+ def new_path
282
+ new_action = self.options[:path_names][:new] if self.options[:path_names]
283
+ new_action ||= ActionController::Base.resources_path_names[:new]
284
+ @new_path ||= "#{path}/#{new_action}"
285
+ end
286
+
287
+ def shallow_path_prefix
288
+ @shallow_path_prefix ||= @options[:shallow] ? @options[:namespace].try(:sub, /\/$/, '') : path_prefix
289
+ end
290
+
291
+ def member_path
292
+ @member_path ||= "#{shallow_path_prefix}/#{path_segment}/:id"
293
+ end
294
+
295
+ def nesting_path_prefix
296
+ @nesting_path_prefix ||= "#{shallow_path_prefix}/#{path_segment}/:#{singular}_id"
297
+ end
298
+
299
+ def shallow_name_prefix
300
+ @shallow_name_prefix ||= @options[:shallow] ? @options[:namespace].try(:gsub, /\//, '_') : name_prefix
301
+ end
302
+
303
+ def nesting_name_prefix
304
+ "#{shallow_name_prefix}#{singular}_"
305
+ end
306
+
307
+ def action_separator
308
+ @action_separator ||= ActionController::Base.resource_action_separator
309
+ end
310
+
311
+ def uncountable?
312
+ @singular.to_s == @plural.to_s
313
+ end
314
+
315
+ def has_action?(action)
316
+ !DEFAULT_ACTIONS.include?(action) || action_allowed?(action)
317
+ end
318
+
319
+ protected
320
+ def arrange_actions
321
+ @collection_methods = arrange_actions_by_methods(options.delete(:collection))
322
+ @member_methods = arrange_actions_by_methods(options.delete(:member))
323
+ @new_methods = arrange_actions_by_methods(options.delete(:new))
324
+ end
325
+
326
+ def add_default_actions
327
+ add_default_action(member_methods, :get, :edit)
328
+ add_default_action(new_methods, :get, :new)
329
+ end
330
+
331
+ def set_allowed_actions
332
+ only, except = @options.values_at(:only, :except)
333
+ @allowed_actions ||= {}
334
+
335
+ if only == :all || except == :none
336
+ only = nil
337
+ except = []
338
+ elsif only == :none || except == :all
339
+ only = []
340
+ except = nil
341
+ end
342
+
343
+ if only
344
+ @allowed_actions[:only] = Array(only).map {|a| a.to_sym }
345
+ elsif except
346
+ @allowed_actions[:except] = Array(except).map {|a| a.to_sym }
347
+ end
348
+ end
349
+
350
+ def action_allowed?(action)
351
+ only, except = @allowed_actions.values_at(:only, :except)
352
+ (!only || only.include?(action)) && (!except || !except.include?(action))
353
+ end
354
+
355
+ def set_prefixes
356
+ @path_prefix = options.delete(:path_prefix)
357
+ @name_prefix = options.delete(:name_prefix)
358
+ end
359
+
360
+ def arrange_actions_by_methods(actions)
361
+ (actions || {}).inject({}) do |flipped_hash, (key, value)|
362
+ (flipped_hash[value] ||= []) << key
363
+ flipped_hash
364
+ end
365
+ end
366
+
367
+ def add_default_action(collection, method, action)
368
+ (collection[method] ||= []).unshift(action)
369
+ end
370
+ end
371
+
372
+ class SingletonResource < Resource #:nodoc:
373
+ def initialize(entity, options)
374
+ @singular = @plural = entity
375
+ options[:controller] ||= @singular.to_s.pluralize
376
+ super
377
+ end
378
+
379
+ alias_method :shallow_path_prefix, :path_prefix
380
+ alias_method :shallow_name_prefix, :name_prefix
381
+ alias_method :member_path, :path
382
+ alias_method :nesting_path_prefix, :path
383
+ end
384
+
385
+ # Creates named routes for implementing verb-oriented controllers
386
+ # for a collection \resource.
387
+ #
388
+ # For example:
389
+ #
390
+ # map.resources :messages
391
+ #
392
+ # will map the following actions in the corresponding controller:
393
+ #
394
+ # class MessagesController < ActionController::Base
395
+ # # GET messages_url
396
+ # def index
397
+ # # return all messages
398
+ # end
399
+ #
400
+ # # GET new_message_url
401
+ # def new
402
+ # # return an HTML form for describing a new message
403
+ # end
404
+ #
405
+ # # POST messages_url
406
+ # def create
407
+ # # create a new message
408
+ # end
409
+ #
410
+ # # GET message_url(:id => 1)
411
+ # def show
412
+ # # find and return a specific message
413
+ # end
414
+ #
415
+ # # GET edit_message_url(:id => 1)
416
+ # def edit
417
+ # # return an HTML form for editing a specific message
418
+ # end
419
+ #
420
+ # # PUT message_url(:id => 1)
421
+ # def update
422
+ # # find and update a specific message
423
+ # end
424
+ #
425
+ # # DELETE message_url(:id => 1)
426
+ # def destroy
427
+ # # delete a specific message
428
+ # end
429
+ # end
430
+ #
431
+ # Along with the routes themselves, +resources+ generates named routes for use in
432
+ # controllers and views. <tt>map.resources :messages</tt> produces the following named routes and helpers:
433
+ #
434
+ # Named Route Helpers
435
+ # ============ =====================================================
436
+ # messages messages_url, hash_for_messages_url,
437
+ # messages_path, hash_for_messages_path
438
+ #
439
+ # message message_url(id), hash_for_message_url(id),
440
+ # message_path(id), hash_for_message_path(id)
441
+ #
442
+ # new_message new_message_url, hash_for_new_message_url,
443
+ # new_message_path, hash_for_new_message_path
444
+ #
445
+ # edit_message edit_message_url(id), hash_for_edit_message_url(id),
446
+ # edit_message_path(id), hash_for_edit_message_path(id)
447
+ #
448
+ # You can use these helpers instead of +url_for+ or methods that take +url_for+ parameters. For example:
449
+ #
450
+ # redirect_to :controller => 'messages', :action => 'index'
451
+ # # and
452
+ # <%= link_to "edit this message", :controller => 'messages', :action => 'edit', :id => @message.id %>
453
+ #
454
+ # now become:
455
+ #
456
+ # redirect_to messages_url
457
+ # # and
458
+ # <%= link_to "edit this message", edit_message_url(@message) # calls @message.id automatically
459
+ #
460
+ # Since web browsers don't support the PUT and DELETE verbs, you will need to add a parameter '_method' to your
461
+ # form tags. The form helpers make this a little easier. For an update form with a <tt>@message</tt> object:
462
+ #
463
+ # <%= form_tag message_path(@message), :method => :put %>
464
+ #
465
+ # or
466
+ #
467
+ # <% form_for :message, @message, :url => message_path(@message), :html => {:method => :put} do |f| %>
468
+ #
469
+ # or
470
+ #
471
+ # <% form_for @message do |f| %>
472
+ #
473
+ # which takes into account whether <tt>@message</tt> is a new record or not and generates the
474
+ # path and method accordingly.
475
+ #
476
+ # The +resources+ method accepts the following options to customize the resulting routes:
477
+ # * <tt>:collection</tt> - Add named routes for other actions that operate on the collection.
478
+ # Takes a hash of <tt>#{action} => #{method}</tt>, where method is <tt>:get</tt>/<tt>:post</tt>/<tt>:put</tt>/<tt>:delete</tt>,
479
+ # an array of any of the previous, or <tt>:any</tt> if the method does not matter.
480
+ # These routes map to a URL like /messages/rss, with a route of +rss_messages_url+.
481
+ # * <tt>:member</tt> - Same as <tt>:collection</tt>, but for actions that operate on a specific member.
482
+ # * <tt>:new</tt> - Same as <tt>:collection</tt>, but for actions that operate on the new \resource action.
483
+ # * <tt>:controller</tt> - Specify the controller name for the routes.
484
+ # * <tt>:singular</tt> - Specify the singular name used in the member routes.
485
+ # * <tt>:requirements</tt> - Set custom routing parameter requirements; this is a hash of either
486
+ # regular expressions (which must match for the route to match) or extra parameters. For example:
487
+ #
488
+ # map.resource :profile, :path_prefix => ':name', :requirements => { :name => /[a-zA-Z]+/, :extra => 'value' }
489
+ #
490
+ # will only match if the first part is alphabetic, and will pass the parameter :extra to the controller.
491
+ # * <tt>:conditions</tt> - Specify custom routing recognition conditions. \Resources sets the <tt>:method</tt> value for the method-specific routes.
492
+ # * <tt>:as</tt> - Specify a different \resource name to use in the URL path. For example:
493
+ # # products_path == '/productos'
494
+ # map.resources :products, :as => 'productos' do |product|
495
+ # # product_reviews_path(product) == '/productos/1234/comentarios'
496
+ # product.resources :product_reviews, :as => 'comentarios'
497
+ # end
498
+ #
499
+ # * <tt>:has_one</tt> - Specify nested \resources, this is a shorthand for mapping singleton \resources beneath the current.
500
+ # * <tt>:has_many</tt> - Same has <tt>:has_one</tt>, but for plural \resources.
501
+ #
502
+ # You may directly specify the routing association with +has_one+ and +has_many+ like:
503
+ #
504
+ # map.resources :notes, :has_one => :author, :has_many => [:comments, :attachments]
505
+ #
506
+ # This is the same as:
507
+ #
508
+ # map.resources :notes do |notes|
509
+ # notes.resource :author
510
+ # notes.resources :comments
511
+ # notes.resources :attachments
512
+ # end
513
+ #
514
+ # * <tt>:path_names</tt> - Specify different path names for the actions. For example:
515
+ # # new_products_path == '/productos/nuevo'
516
+ # # bids_product_path(1) == '/productos/1/licitacoes'
517
+ # map.resources :products, :as => 'productos', :member => { :bids => :get }, :path_names => { :new => 'nuevo', :bids => 'licitacoes' }
518
+ #
519
+ # You can also set default action names from an environment, like this:
520
+ # config.action_controller.resources_path_names = { :new => 'nuevo', :edit => 'editar' }
521
+ #
522
+ # * <tt>:path_prefix</tt> - Set a prefix to the routes with required route variables.
523
+ #
524
+ # Weblog comments usually belong to a post, so you might use +resources+ like:
525
+ #
526
+ # map.resources :articles
527
+ # map.resources :comments, :path_prefix => '/articles/:article_id'
528
+ #
529
+ # You can nest +resources+ calls to set this automatically:
530
+ #
531
+ # map.resources :articles do |article|
532
+ # article.resources :comments
533
+ # end
534
+ #
535
+ # The comment \resources work the same, but must now include a value for <tt>:article_id</tt>.
536
+ #
537
+ # article_comments_url(@article)
538
+ # article_comment_url(@article, @comment)
539
+ #
540
+ # article_comments_url(:article_id => @article)
541
+ # article_comment_url(:article_id => @article, :id => @comment)
542
+ #
543
+ # If you don't want to load all objects from the database you might want to use the <tt>article_id</tt> directly:
544
+ #
545
+ # articles_comments_url(@comment.article_id, @comment)
546
+ #
547
+ # * <tt>:name_prefix</tt> - Define a prefix for all generated routes, usually ending in an underscore.
548
+ # Use this if you have named routes that may clash.
549
+ #
550
+ # map.resources :tags, :path_prefix => '/books/:book_id', :name_prefix => 'book_'
551
+ # map.resources :tags, :path_prefix => '/toys/:toy_id', :name_prefix => 'toy_'
552
+ #
553
+ # You may also use <tt>:name_prefix</tt> to override the generic named routes in a nested \resource:
554
+ #
555
+ # map.resources :articles do |article|
556
+ # article.resources :comments, :name_prefix => nil
557
+ # end
558
+ #
559
+ # This will yield named \resources like so:
560
+ #
561
+ # comments_url(@article)
562
+ # comment_url(@article, @comment)
563
+ #
564
+ # * <tt>:shallow</tt> - If true, paths for nested resources which reference a specific member
565
+ # (ie. those with an :id parameter) will not use the parent path prefix or name prefix.
566
+ #
567
+ # The <tt>:shallow</tt> option is inherited by any nested resource(s).
568
+ #
569
+ # For example, 'users', 'posts' and 'comments' all use shallow paths with the following nested resources:
570
+ #
571
+ # map.resources :users, :shallow => true do |user|
572
+ # user.resources :posts do |post|
573
+ # post.resources :comments
574
+ # end
575
+ # end
576
+ # # --> GET /users/1/posts (maps to the PostsController#index action as usual)
577
+ # # also adds the usual named route called "user_posts"
578
+ # # --> GET /posts/2 (maps to the PostsController#show action as if it were not nested)
579
+ # # also adds the named route called "post"
580
+ # # --> GET /posts/2/comments (maps to the CommentsController#index action)
581
+ # # also adds the named route called "post_comments"
582
+ # # --> GET /comments/2 (maps to the CommentsController#show action as if it were not nested)
583
+ # # also adds the named route called "comment"
584
+ #
585
+ # You may also use <tt>:shallow</tt> in combination with the +has_one+ and +has_many+ shorthand notations like:
586
+ #
587
+ # map.resources :users, :has_many => { :posts => :comments }, :shallow => true
588
+ #
589
+ # * <tt>:only</tt> and <tt>:except</tt> - Specify which of the seven default actions should be routed to.
590
+ #
591
+ # <tt>:only</tt> and <tt>:except</tt> may be set to <tt>:all</tt>, <tt>:none</tt>, an action name or a
592
+ # list of action names. By default, routes are generated for all seven actions.
593
+ #
594
+ # For example:
595
+ #
596
+ # map.resources :posts, :only => [:index, :show] do |post|
597
+ # post.resources :comments, :except => [:update, :destroy]
598
+ # end
599
+ # # --> GET /posts (maps to the PostsController#index action)
600
+ # # --> POST /posts (fails)
601
+ # # --> GET /posts/1 (maps to the PostsController#show action)
602
+ # # --> DELETE /posts/1 (fails)
603
+ # # --> POST /posts/1/comments (maps to the CommentsController#create action)
604
+ # # --> PUT /posts/1/comments/1 (fails)
605
+ #
606
+ # If <tt>map.resources</tt> is called with multiple resources, they all get the same options applied.
607
+ #
608
+ # Examples:
609
+ #
610
+ # map.resources :messages, :path_prefix => "/thread/:thread_id"
611
+ # # --> GET /thread/7/messages/1
612
+ #
613
+ # map.resources :messages, :collection => { :rss => :get }
614
+ # # --> GET /messages/rss (maps to the #rss action)
615
+ # # also adds a named route called "rss_messages"
616
+ #
617
+ # map.resources :messages, :member => { :mark => :post }
618
+ # # --> POST /messages/1/mark (maps to the #mark action)
619
+ # # also adds a named route called "mark_message"
620
+ #
621
+ # map.resources :messages, :new => { :preview => :post }
622
+ # # --> POST /messages/new/preview (maps to the #preview action)
623
+ # # also adds a named route called "preview_new_message"
624
+ #
625
+ # map.resources :messages, :new => { :new => :any, :preview => :post }
626
+ # # --> POST /messages/new/preview (maps to the #preview action)
627
+ # # also adds a named route called "preview_new_message"
628
+ # # --> /messages/new can be invoked via any request method
629
+ #
630
+ # map.resources :messages, :controller => "categories",
631
+ # :path_prefix => "/category/:category_id",
632
+ # :name_prefix => "category_"
633
+ # # --> GET /categories/7/messages/1
634
+ # # has named route "category_message"
635
+ #
636
+ # The +resources+ method sets HTTP method restrictions on the routes it generates. For example, making an
637
+ # HTTP POST on <tt>new_message_url</tt> will raise a RoutingError exception. The default route in
638
+ # <tt>config/routes.rb</tt> overrides this and allows invalid HTTP methods for \resource routes.
639
+ def resources(*entities, &block)
640
+ options = entities.extract_options!
641
+ entities.each { |entity| map_resource(entity, options.dup, &block) }
642
+ end
643
+
644
+ # Creates named routes for implementing verb-oriented controllers for a singleton \resource.
645
+ # A singleton \resource is global to its current context. For unnested singleton \resources,
646
+ # the \resource is global to the current user visiting the application, such as a user's
647
+ # <tt>/account</tt> profile. For nested singleton \resources, the \resource is global to its parent
648
+ # \resource, such as a <tt>projects</tt> \resource that <tt>has_one :project_manager</tt>.
649
+ # The <tt>project_manager</tt> should be mapped as a singleton \resource under <tt>projects</tt>:
650
+ #
651
+ # map.resources :projects do |project|
652
+ # project.resource :project_manager
653
+ # end
654
+ #
655
+ # See +resources+ for general conventions. These are the main differences:
656
+ # * A singular name is given to <tt>map.resource</tt>. The default controller name is still taken from the plural name.
657
+ # * To specify a custom plural name, use the <tt>:plural</tt> option. There is no <tt>:singular</tt> option.
658
+ # * No default index route is created for the singleton \resource controller.
659
+ # * When nesting singleton \resources, only the singular name is used as the path prefix (example: 'account/messages/1')
660
+ #
661
+ # For example:
662
+ #
663
+ # map.resource :account
664
+ #
665
+ # maps these actions in the Accounts controller:
666
+ #
667
+ # class AccountsController < ActionController::Base
668
+ # # GET new_account_url
669
+ # def new
670
+ # # return an HTML form for describing the new account
671
+ # end
672
+ #
673
+ # # POST account_url
674
+ # def create
675
+ # # create an account
676
+ # end
677
+ #
678
+ # # GET account_url
679
+ # def show
680
+ # # find and return the account
681
+ # end
682
+ #
683
+ # # GET edit_account_url
684
+ # def edit
685
+ # # return an HTML form for editing the account
686
+ # end
687
+ #
688
+ # # PUT account_url
689
+ # def update
690
+ # # find and update the account
691
+ # end
692
+ #
693
+ # # DELETE account_url
694
+ # def destroy
695
+ # # delete the account
696
+ # end
697
+ # end
698
+ #
699
+ # Along with the routes themselves, +resource+ generates named routes for
700
+ # use in controllers and views. <tt>map.resource :account</tt> produces
701
+ # these named routes and helpers:
702
+ #
703
+ # Named Route Helpers
704
+ # ============ =============================================
705
+ # account account_url, hash_for_account_url,
706
+ # account_path, hash_for_account_path
707
+ #
708
+ # new_account new_account_url, hash_for_new_account_url,
709
+ # new_account_path, hash_for_new_account_path
710
+ #
711
+ # edit_account edit_account_url, hash_for_edit_account_url,
712
+ # edit_account_path, hash_for_edit_account_path
713
+ def resource(*entities, &block)
714
+ options = entities.extract_options!
715
+ entities.each { |entity| map_singleton_resource(entity, options.dup, &block) }
716
+ end
717
+
718
+ private
719
+ def map_resource(entities, options = {}, &block)
720
+ resource = Resource.new(entities, options)
721
+
722
+ with_options :controller => resource.controller do |map|
723
+ map_associations(resource, options)
724
+
725
+ if block_given?
726
+ with_options(options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix), &block)
727
+ end
728
+
729
+ map_collection_actions(map, resource)
730
+ map_default_collection_actions(map, resource)
731
+ map_new_actions(map, resource)
732
+ map_member_actions(map, resource)
733
+ end
734
+ end
735
+
736
+ def map_singleton_resource(entities, options = {}, &block)
737
+ resource = SingletonResource.new(entities, options)
738
+
739
+ with_options :controller => resource.controller do |map|
740
+ map_associations(resource, options)
741
+
742
+ if block_given?
743
+ with_options(options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix), &block)
744
+ end
745
+
746
+ map_collection_actions(map, resource)
747
+ map_new_actions(map, resource)
748
+ map_member_actions(map, resource)
749
+ map_default_singleton_actions(map, resource)
750
+ end
751
+ end
752
+
753
+ def map_associations(resource, options)
754
+ map_has_many_associations(resource, options.delete(:has_many), options) if options[:has_many]
755
+
756
+ path_prefix = "#{options.delete(:path_prefix)}#{resource.nesting_path_prefix}"
757
+ name_prefix = "#{options.delete(:name_prefix)}#{resource.nesting_name_prefix}"
758
+
759
+ Array(options[:has_one]).each do |association|
760
+ resource(association, options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => path_prefix, :name_prefix => name_prefix))
761
+ end
762
+ end
763
+
764
+ def map_has_many_associations(resource, associations, options)
765
+ case associations
766
+ when Hash
767
+ associations.each do |association,has_many|
768
+ map_has_many_associations(resource, association, options.merge(:has_many => has_many))
769
+ end
770
+ when Array
771
+ associations.each do |association|
772
+ map_has_many_associations(resource, association, options)
773
+ end
774
+ when Symbol, String
775
+ resources(associations, options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix, :has_many => options[:has_many]))
776
+ else
777
+ end
778
+ end
779
+
780
+ def map_collection_actions(map, resource)
781
+ resource.collection_methods.each do |method, actions|
782
+ actions.each do |action|
783
+ [method].flatten.each do |m|
784
+ action_path = resource.options[:path_names][action] if resource.options[:path_names].is_a?(Hash)
785
+ action_path ||= action
786
+
787
+ map_resource_routes(map, resource, action, "#{resource.path}#{resource.action_separator}#{action_path}", "#{action}_#{resource.name_prefix}#{resource.plural}", m)
788
+ end
789
+ end
790
+ end
791
+ end
792
+
793
+ def map_default_collection_actions(map, resource)
794
+ index_route_name = "#{resource.name_prefix}#{resource.plural}"
795
+
796
+ if resource.uncountable?
797
+ index_route_name << "_index"
798
+ end
799
+
800
+ map_resource_routes(map, resource, :index, resource.path, index_route_name)
801
+ map_resource_routes(map, resource, :create, resource.path, index_route_name)
802
+ end
803
+
804
+ def map_default_singleton_actions(map, resource)
805
+ map_resource_routes(map, resource, :create, resource.path, "#{resource.shallow_name_prefix}#{resource.singular}")
806
+ end
807
+
808
+ def map_new_actions(map, resource)
809
+ resource.new_methods.each do |method, actions|
810
+ actions.each do |action|
811
+ route_path = resource.new_path
812
+ route_name = "new_#{resource.name_prefix}#{resource.singular}"
813
+
814
+ unless action == :new
815
+ route_path = "#{route_path}#{resource.action_separator}#{action}"
816
+ route_name = "#{action}_#{route_name}"
817
+ end
818
+
819
+ map_resource_routes(map, resource, action, route_path, route_name, method)
820
+ end
821
+ end
822
+ end
823
+
824
+ def map_member_actions(map, resource)
825
+ resource.member_methods.each do |method, actions|
826
+ actions.each do |action|
827
+ [method].flatten.each do |m|
828
+ action_path = resource.options[:path_names][action] if resource.options[:path_names].is_a?(Hash)
829
+ action_path ||= ActionController::Base.resources_path_names[action] || action
830
+
831
+ map_resource_routes(map, resource, action, "#{resource.member_path}#{resource.action_separator}#{action_path}", "#{action}_#{resource.shallow_name_prefix}#{resource.singular}", m, { :force_id => true })
832
+ end
833
+ end
834
+ end
835
+
836
+ route_path = "#{resource.shallow_name_prefix}#{resource.singular}"
837
+ map_resource_routes(map, resource, :show, resource.member_path, route_path)
838
+ map_resource_routes(map, resource, :update, resource.member_path, route_path)
839
+ map_resource_routes(map, resource, :destroy, resource.member_path, route_path)
840
+ end
841
+
842
+ def map_resource_routes(map, resource, action, route_path, route_name = nil, method = nil, resource_options = {} )
843
+ if resource.has_action?(action)
844
+ action_options = action_options_for(action, resource, method, resource_options)
845
+ formatted_route_path = "#{route_path}.:format"
846
+
847
+ if route_name && @set.named_routes[route_name.to_sym].nil?
848
+ map.named_route(route_name, formatted_route_path, action_options)
849
+ else
850
+ map.connect(formatted_route_path, action_options)
851
+ end
852
+ end
853
+ end
854
+
855
+ def add_conditions_for(conditions, method)
856
+ returning({:conditions => conditions.dup}) do |options|
857
+ options[:conditions][:method] = method unless method == :any
858
+ end
859
+ end
860
+
861
+ def action_options_for(action, resource, method = nil, resource_options = {})
862
+ default_options = { :action => action.to_s }
863
+ require_id = !resource.kind_of?(SingletonResource)
864
+ force_id = resource_options[:force_id] && !resource.kind_of?(SingletonResource)
865
+
866
+ case default_options[:action]
867
+ when "index", "new"; default_options.merge(add_conditions_for(resource.conditions, method || :get)).merge(resource.requirements)
868
+ when "create"; default_options.merge(add_conditions_for(resource.conditions, method || :post)).merge(resource.requirements)
869
+ when "show", "edit"; default_options.merge(add_conditions_for(resource.conditions, method || :get)).merge(resource.requirements(require_id))
870
+ when "update"; default_options.merge(add_conditions_for(resource.conditions, method || :put)).merge(resource.requirements(require_id))
871
+ when "destroy"; default_options.merge(add_conditions_for(resource.conditions, method || :delete)).merge(resource.requirements(require_id))
872
+ else default_options.merge(add_conditions_for(resource.conditions, method)).merge(resource.requirements(force_id))
873
+ end
874
+ end
875
+ end
876
+ end
877
+ end