eactionpack 2.1.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 (338) hide show
  1. data/CHANGELOG +7 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +469 -0
  4. data/RUNNING_UNIT_TESTS +24 -0
  5. data/Rakefile +146 -0
  6. data/install.rb +30 -0
  7. data/lib/action_controller.rb +79 -0
  8. data/lib/action_controller/assertions.rb +69 -0
  9. data/lib/action_controller/assertions/dom_assertions.rb +39 -0
  10. data/lib/action_controller/assertions/model_assertions.rb +20 -0
  11. data/lib/action_controller/assertions/response_assertions.rb +172 -0
  12. data/lib/action_controller/assertions/routing_assertions.rb +146 -0
  13. data/lib/action_controller/assertions/selector_assertions.rb +491 -0
  14. data/lib/action_controller/assertions/tag_assertions.rb +130 -0
  15. data/lib/action_controller/base.rb +1288 -0
  16. data/lib/action_controller/benchmarking.rb +94 -0
  17. data/lib/action_controller/caching.rb +72 -0
  18. data/lib/action_controller/caching/actions.rb +144 -0
  19. data/lib/action_controller/caching/fragments.rb +138 -0
  20. data/lib/action_controller/caching/pages.rb +154 -0
  21. data/lib/action_controller/caching/sql_cache.rb +18 -0
  22. data/lib/action_controller/caching/sweeping.rb +97 -0
  23. data/lib/action_controller/cgi_ext.rb +16 -0
  24. data/lib/action_controller/cgi_ext/cookie.rb +110 -0
  25. data/lib/action_controller/cgi_ext/query_extension.rb +22 -0
  26. data/lib/action_controller/cgi_ext/session.rb +73 -0
  27. data/lib/action_controller/cgi_ext/stdinput.rb +24 -0
  28. data/lib/action_controller/cgi_process.rb +223 -0
  29. data/lib/action_controller/components.rb +166 -0
  30. data/lib/action_controller/cookies.rb +96 -0
  31. data/lib/action_controller/dispatcher.rb +162 -0
  32. data/lib/action_controller/filters.rb +642 -0
  33. data/lib/action_controller/flash.rb +172 -0
  34. data/lib/action_controller/headers.rb +31 -0
  35. data/lib/action_controller/helpers.rb +221 -0
  36. data/lib/action_controller/http_authentication.rb +124 -0
  37. data/lib/action_controller/integration.rb +634 -0
  38. data/lib/action_controller/layout.rb +309 -0
  39. data/lib/action_controller/mime_responds.rb +173 -0
  40. data/lib/action_controller/mime_type.rb +186 -0
  41. data/lib/action_controller/mime_types.rb +20 -0
  42. data/lib/action_controller/polymorphic_routes.rb +191 -0
  43. data/lib/action_controller/record_identifier.rb +102 -0
  44. data/lib/action_controller/request.rb +764 -0
  45. data/lib/action_controller/request_forgery_protection.rb +140 -0
  46. data/lib/action_controller/request_profiler.rb +169 -0
  47. data/lib/action_controller/rescue.rb +258 -0
  48. data/lib/action_controller/resources.rb +572 -0
  49. data/lib/action_controller/response.rb +76 -0
  50. data/lib/action_controller/routing.rb +387 -0
  51. data/lib/action_controller/routing/builder.rb +203 -0
  52. data/lib/action_controller/routing/optimisations.rb +120 -0
  53. data/lib/action_controller/routing/recognition_optimisation.rb +162 -0
  54. data/lib/action_controller/routing/route.rb +240 -0
  55. data/lib/action_controller/routing/route_set.rb +436 -0
  56. data/lib/action_controller/routing/routing_ext.rb +46 -0
  57. data/lib/action_controller/routing/segments.rb +283 -0
  58. data/lib/action_controller/session/active_record_store.rb +340 -0
  59. data/lib/action_controller/session/cookie_store.rb +166 -0
  60. data/lib/action_controller/session/drb_server.rb +32 -0
  61. data/lib/action_controller/session/drb_store.rb +35 -0
  62. data/lib/action_controller/session/mem_cache_store.rb +98 -0
  63. data/lib/action_controller/session_management.rb +158 -0
  64. data/lib/action_controller/status_codes.rb +88 -0
  65. data/lib/action_controller/streaming.rb +155 -0
  66. data/lib/action_controller/templates/rescues/_request_and_response.erb +24 -0
  67. data/lib/action_controller/templates/rescues/_trace.erb +26 -0
  68. data/lib/action_controller/templates/rescues/diagnostics.erb +11 -0
  69. data/lib/action_controller/templates/rescues/layout.erb +29 -0
  70. data/lib/action_controller/templates/rescues/missing_template.erb +2 -0
  71. data/lib/action_controller/templates/rescues/routing_error.erb +10 -0
  72. data/lib/action_controller/templates/rescues/template_error.erb +21 -0
  73. data/lib/action_controller/templates/rescues/unknown_action.erb +2 -0
  74. data/lib/action_controller/test_case.rb +83 -0
  75. data/lib/action_controller/test_process.rb +526 -0
  76. data/lib/action_controller/url_rewriter.rb +142 -0
  77. data/lib/action_controller/vendor/html-scanner/html/document.rb +68 -0
  78. data/lib/action_controller/vendor/html-scanner/html/node.rb +537 -0
  79. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +173 -0
  80. data/lib/action_controller/vendor/html-scanner/html/selector.rb +828 -0
  81. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +105 -0
  82. data/lib/action_controller/vendor/html-scanner/html/version.rb +11 -0
  83. data/lib/action_controller/verification.rb +130 -0
  84. data/lib/action_pack.rb +24 -0
  85. data/lib/action_pack/version.rb +9 -0
  86. data/lib/action_view.rb +44 -0
  87. data/lib/action_view/base.rb +335 -0
  88. data/lib/action_view/helpers/active_record_helper.rb +276 -0
  89. data/lib/action_view/helpers/asset_tag_helper.rb +599 -0
  90. data/lib/action_view/helpers/atom_feed_helper.rb +143 -0
  91. data/lib/action_view/helpers/benchmark_helper.rb +33 -0
  92. data/lib/action_view/helpers/cache_helper.rb +40 -0
  93. data/lib/action_view/helpers/capture_helper.rb +161 -0
  94. data/lib/action_view/helpers/date_helper.rb +711 -0
  95. data/lib/action_view/helpers/debug_helper.rb +31 -0
  96. data/lib/action_view/helpers/form_helper.rb +767 -0
  97. data/lib/action_view/helpers/form_options_helper.rb +458 -0
  98. data/lib/action_view/helpers/form_tag_helper.rb +458 -0
  99. data/lib/action_view/helpers/javascript_helper.rb +148 -0
  100. data/lib/action_view/helpers/number_helper.rb +186 -0
  101. data/lib/action_view/helpers/record_identification_helper.rb +20 -0
  102. data/lib/action_view/helpers/record_tag_helper.rb +59 -0
  103. data/lib/action_view/helpers/sanitize_helper.rb +229 -0
  104. data/lib/action_view/helpers/tag_helper.rb +134 -0
  105. data/lib/action_view/helpers/text_helper.rb +507 -0
  106. data/lib/action_view/helpers/url_helper.rb +573 -0
  107. data/lib/action_view/inline_template.rb +20 -0
  108. data/lib/action_view/partial_template.rb +70 -0
  109. data/lib/action_view/partials.rb +158 -0
  110. data/lib/action_view/template.rb +125 -0
  111. data/lib/action_view/template_error.rb +110 -0
  112. data/lib/action_view/template_finder.rb +176 -0
  113. data/lib/action_view/template_handler.rb +34 -0
  114. data/lib/action_view/template_handlers/builder.rb +27 -0
  115. data/lib/action_view/template_handlers/compilable.rb +128 -0
  116. data/lib/action_view/template_handlers/erb.rb +56 -0
  117. data/lib/action_view/test_case.rb +58 -0
  118. data/lib/actionpack.rb +1 -0
  119. data/test/abstract_unit.rb +36 -0
  120. data/test/active_record_unit.rb +105 -0
  121. data/test/activerecord/active_record_store_test.rb +141 -0
  122. data/test/activerecord/render_partial_with_record_identification_test.rb +191 -0
  123. data/test/adv_attr_test.rb +20 -0
  124. data/test/controller/action_pack_assertions_test.rb +543 -0
  125. data/test/controller/addresses_render_test.rb +43 -0
  126. data/test/controller/assert_select_test.rb +331 -0
  127. data/test/controller/base_test.rb +219 -0
  128. data/test/controller/benchmark_test.rb +32 -0
  129. data/test/controller/caching_test.rb +581 -0
  130. data/test/controller/capture_test.rb +89 -0
  131. data/test/controller/cgi_test.rb +116 -0
  132. data/test/controller/components_test.rb +140 -0
  133. data/test/controller/content_type_test.rb +139 -0
  134. data/test/controller/controller_fixtures/app/controllers/admin/user_controller.rb +0 -0
  135. data/test/controller/controller_fixtures/app/controllers/user_controller.rb +0 -0
  136. data/test/controller/controller_fixtures/vendor/plugins/bad_plugin/lib/plugin_controller.rb +0 -0
  137. data/test/controller/cookie_test.rb +146 -0
  138. data/test/controller/custom_handler_test.rb +45 -0
  139. data/test/controller/deprecation/deprecated_base_methods_test.rb +37 -0
  140. data/test/controller/dispatcher_test.rb +105 -0
  141. data/test/controller/fake_controllers.rb +33 -0
  142. data/test/controller/fake_models.rb +11 -0
  143. data/test/controller/filter_params_test.rb +49 -0
  144. data/test/controller/filters_test.rb +881 -0
  145. data/test/controller/flash_test.rb +146 -0
  146. data/test/controller/header_test.rb +14 -0
  147. data/test/controller/helper_test.rb +210 -0
  148. data/test/controller/html-scanner/cdata_node_test.rb +15 -0
  149. data/test/controller/html-scanner/document_test.rb +148 -0
  150. data/test/controller/html-scanner/node_test.rb +89 -0
  151. data/test/controller/html-scanner/sanitizer_test.rb +269 -0
  152. data/test/controller/html-scanner/tag_node_test.rb +238 -0
  153. data/test/controller/html-scanner/text_node_test.rb +50 -0
  154. data/test/controller/html-scanner/tokenizer_test.rb +131 -0
  155. data/test/controller/http_authentication_test.rb +54 -0
  156. data/test/controller/integration_test.rb +252 -0
  157. data/test/controller/integration_upload_test.rb +43 -0
  158. data/test/controller/layout_test.rb +255 -0
  159. data/test/controller/mime_responds_test.rb +514 -0
  160. data/test/controller/mime_type_test.rb +84 -0
  161. data/test/controller/new_render_test.rb +843 -0
  162. data/test/controller/polymorphic_routes_test.rb +174 -0
  163. data/test/controller/record_identifier_test.rb +139 -0
  164. data/test/controller/redirect_test.rb +289 -0
  165. data/test/controller/render_test.rb +484 -0
  166. data/test/controller/request_forgery_protection_test.rb +305 -0
  167. data/test/controller/request_test.rb +928 -0
  168. data/test/controller/rescue_test.rb +517 -0
  169. data/test/controller/resources_test.rb +873 -0
  170. data/test/controller/routing_test.rb +2464 -0
  171. data/test/controller/selector_test.rb +628 -0
  172. data/test/controller/send_file_test.rb +138 -0
  173. data/test/controller/session/cookie_store_test.rb +258 -0
  174. data/test/controller/session/mem_cache_store_test.rb +181 -0
  175. data/test/controller/session_fixation_test.rb +89 -0
  176. data/test/controller/session_management_test.rb +178 -0
  177. data/test/controller/test_test.rb +695 -0
  178. data/test/controller/url_rewriter_test.rb +310 -0
  179. data/test/controller/verification_test.rb +270 -0
  180. data/test/controller/view_paths_test.rb +140 -0
  181. data/test/controller/webservice_test.rb +229 -0
  182. data/test/fixtures/addresses/list.erb +1 -0
  183. data/test/fixtures/bad_customers/_bad_customer.html.erb +1 -0
  184. data/test/fixtures/companies.yml +24 -0
  185. data/test/fixtures/company.rb +10 -0
  186. data/test/fixtures/content_type/render_default_content_types_for_respond_to.rhtml +1 -0
  187. data/test/fixtures/content_type/render_default_for_js.js.erb +1 -0
  188. data/test/fixtures/content_type/render_default_for_rhtml.rhtml +1 -0
  189. data/test/fixtures/content_type/render_default_for_rxml.rxml +1 -0
  190. data/test/fixtures/customers/_customer.html.erb +1 -0
  191. data/test/fixtures/db_definitions/sqlite.sql +49 -0
  192. data/test/fixtures/developer.rb +9 -0
  193. data/test/fixtures/developers.yml +21 -0
  194. data/test/fixtures/developers_projects.yml +13 -0
  195. data/test/fixtures/fun/games/hello_world.erb +1 -0
  196. data/test/fixtures/functional_caching/_partial.erb +3 -0
  197. data/test/fixtures/functional_caching/fragment_cached.html.erb +2 -0
  198. data/test/fixtures/functional_caching/html_fragment_cached_with_partial.html.erb +1 -0
  199. data/test/fixtures/functional_caching/js_fragment_cached_with_partial.js.rjs +1 -0
  200. data/test/fixtures/good_customers/_good_customer.html.erb +1 -0
  201. data/test/fixtures/helpers/abc_helper.rb +5 -0
  202. data/test/fixtures/helpers/fun/games_helper.rb +3 -0
  203. data/test/fixtures/helpers/fun/pdf_helper.rb +3 -0
  204. data/test/fixtures/layout_tests/alt/hello.rhtml +1 -0
  205. data/test/fixtures/layout_tests/layouts/controller_name_space/nested.rhtml +1 -0
  206. data/test/fixtures/layout_tests/layouts/item.rhtml +1 -0
  207. data/test/fixtures/layout_tests/layouts/layout_test.rhtml +1 -0
  208. data/test/fixtures/layout_tests/layouts/multiple_extensions.html.erb +1 -0
  209. data/test/fixtures/layout_tests/layouts/third_party_template_library.mab +1 -0
  210. data/test/fixtures/layout_tests/views/hello.rhtml +1 -0
  211. data/test/fixtures/layouts/block_with_layout.erb +3 -0
  212. data/test/fixtures/layouts/builder.builder +3 -0
  213. data/test/fixtures/layouts/partial_with_layout.erb +3 -0
  214. data/test/fixtures/layouts/standard.erb +1 -0
  215. data/test/fixtures/layouts/talk_from_action.erb +2 -0
  216. data/test/fixtures/layouts/yield.erb +2 -0
  217. data/test/fixtures/mascot.rb +3 -0
  218. data/test/fixtures/mascots.yml +4 -0
  219. data/test/fixtures/mascots/_mascot.html.erb +1 -0
  220. data/test/fixtures/multipart/binary_file +0 -0
  221. data/test/fixtures/multipart/boundary_problem_file +10 -0
  222. data/test/fixtures/multipart/bracketed_param +5 -0
  223. data/test/fixtures/multipart/large_text_file +10 -0
  224. data/test/fixtures/multipart/mixed_files +0 -0
  225. data/test/fixtures/multipart/mona_lisa.jpg +0 -0
  226. data/test/fixtures/multipart/single_parameter +5 -0
  227. data/test/fixtures/multipart/text_file +10 -0
  228. data/test/fixtures/override/test/hello_world.erb +1 -0
  229. data/test/fixtures/override2/layouts/test/sub.erb +1 -0
  230. data/test/fixtures/post_test/layouts/post.html.erb +1 -0
  231. data/test/fixtures/post_test/layouts/super_post.iphone.erb +1 -0
  232. data/test/fixtures/post_test/post/index.html.erb +1 -0
  233. data/test/fixtures/post_test/post/index.iphone.erb +1 -0
  234. data/test/fixtures/post_test/super_post/index.html.erb +1 -0
  235. data/test/fixtures/post_test/super_post/index.iphone.erb +1 -0
  236. data/test/fixtures/project.rb +3 -0
  237. data/test/fixtures/projects.yml +7 -0
  238. data/test/fixtures/public/404.html +1 -0
  239. data/test/fixtures/public/500.html +1 -0
  240. data/test/fixtures/public/images/rails.png +0 -0
  241. data/test/fixtures/public/javascripts/application.js +1 -0
  242. data/test/fixtures/public/javascripts/bank.js +1 -0
  243. data/test/fixtures/public/javascripts/robber.js +1 -0
  244. data/test/fixtures/public/javascripts/version.1.0.js +1 -0
  245. data/test/fixtures/public/stylesheets/bank.css +1 -0
  246. data/test/fixtures/public/stylesheets/robber.css +1 -0
  247. data/test/fixtures/public/stylesheets/version.1.0.css +1 -0
  248. data/test/fixtures/replies.yml +15 -0
  249. data/test/fixtures/reply.rb +7 -0
  250. data/test/fixtures/respond_to/all_types_with_layout.html.erb +1 -0
  251. data/test/fixtures/respond_to/custom_constant_handling_without_block.mobile.erb +1 -0
  252. data/test/fixtures/respond_to/iphone_with_html_response_type.html.erb +1 -0
  253. data/test/fixtures/respond_to/iphone_with_html_response_type.iphone.erb +1 -0
  254. data/test/fixtures/respond_to/layouts/missing.html.erb +1 -0
  255. data/test/fixtures/respond_to/layouts/standard.html.erb +1 -0
  256. data/test/fixtures/respond_to/layouts/standard.iphone.erb +1 -0
  257. data/test/fixtures/respond_to/using_defaults.html.erb +1 -0
  258. data/test/fixtures/respond_to/using_defaults.js.rjs +1 -0
  259. data/test/fixtures/respond_to/using_defaults.xml.builder +1 -0
  260. data/test/fixtures/respond_to/using_defaults_with_type_list.html.erb +1 -0
  261. data/test/fixtures/respond_to/using_defaults_with_type_list.js.rjs +1 -0
  262. data/test/fixtures/respond_to/using_defaults_with_type_list.xml.builder +1 -0
  263. data/test/fixtures/scope/test/modgreet.erb +1 -0
  264. data/test/fixtures/shared.html.erb +1 -0
  265. data/test/fixtures/symlink_parent/symlinked_layout.erb +5 -0
  266. data/test/fixtures/test/_customer.erb +1 -0
  267. data/test/fixtures/test/_customer_counter.erb +1 -0
  268. data/test/fixtures/test/_customer_greeting.erb +1 -0
  269. data/test/fixtures/test/_form.erb +1 -0
  270. data/test/fixtures/test/_hash_greeting.erb +1 -0
  271. data/test/fixtures/test/_hash_object.erb +2 -0
  272. data/test/fixtures/test/_hello.builder +1 -0
  273. data/test/fixtures/test/_labelling_form.erb +1 -0
  274. data/test/fixtures/test/_layout_for_partial.html.erb +3 -0
  275. data/test/fixtures/test/_partial.erb +1 -0
  276. data/test/fixtures/test/_partial.html.erb +1 -0
  277. data/test/fixtures/test/_partial.js.erb +1 -0
  278. data/test/fixtures/test/_partial_for_use_in_layout.html.erb +1 -0
  279. data/test/fixtures/test/_partial_only.erb +1 -0
  280. data/test/fixtures/test/_person.erb +2 -0
  281. data/test/fixtures/test/_raise.html.erb +1 -0
  282. data/test/fixtures/test/action_talk_to_layout.erb +2 -0
  283. data/test/fixtures/test/block_content_for.erb +2 -0
  284. data/test/fixtures/test/calling_partial_with_layout.html.erb +1 -0
  285. data/test/fixtures/test/capturing.erb +4 -0
  286. data/test/fixtures/test/content_for.erb +2 -0
  287. data/test/fixtures/test/content_for_concatenated.erb +3 -0
  288. data/test/fixtures/test/content_for_with_parameter.erb +2 -0
  289. data/test/fixtures/test/delete_with_js.rjs +2 -0
  290. data/test/fixtures/test/dot.directory/render_file_with_ivar.erb +1 -0
  291. data/test/fixtures/test/enum_rjs_test.rjs +6 -0
  292. data/test/fixtures/test/erb_content_for.erb +2 -0
  293. data/test/fixtures/test/formatted_html_erb.html.erb +1 -0
  294. data/test/fixtures/test/formatted_xml_erb.builder +1 -0
  295. data/test/fixtures/test/formatted_xml_erb.html.erb +1 -0
  296. data/test/fixtures/test/formatted_xml_erb.xml.erb +1 -0
  297. data/test/fixtures/test/greeting.erb +1 -0
  298. data/test/fixtures/test/greeting.js.rjs +1 -0
  299. data/test/fixtures/test/hello.builder +4 -0
  300. data/test/fixtures/test/hello_world.erb +1 -0
  301. data/test/fixtures/test/hello_world_container.builder +3 -0
  302. data/test/fixtures/test/hello_world_from_rxml.builder +4 -0
  303. data/test/fixtures/test/hello_world_with_layout_false.erb +1 -0
  304. data/test/fixtures/test/hello_xml_world.builder +11 -0
  305. data/test/fixtures/test/list.erb +1 -0
  306. data/test/fixtures/test/non_erb_block_content_for.builder +4 -0
  307. data/test/fixtures/test/potential_conflicts.erb +4 -0
  308. data/test/fixtures/test/render_file_from_template.html.erb +1 -0
  309. data/test/fixtures/test/render_file_with_ivar.erb +1 -0
  310. data/test/fixtures/test/render_file_with_locals.erb +1 -0
  311. data/test/fixtures/test/render_to_string_test.erb +1 -0
  312. data/test/fixtures/test/update_element_with_capture.erb +9 -0
  313. data/test/fixtures/test/using_layout_around_block.html.erb +1 -0
  314. data/test/fixtures/topic.rb +3 -0
  315. data/test/fixtures/topics.yml +22 -0
  316. data/test/fixtures/topics/_topic.html.erb +1 -0
  317. data/test/template/active_record_helper_test.rb +268 -0
  318. data/test/template/asset_tag_helper_test.rb +514 -0
  319. data/test/template/atom_feed_helper_test.rb +179 -0
  320. data/test/template/benchmark_helper_test.rb +60 -0
  321. data/test/template/date_helper_test.rb +1791 -0
  322. data/test/template/deprecated_erb_variable_test.rb +9 -0
  323. data/test/template/erb_util_test.rb +24 -0
  324. data/test/template/form_helper_test.rb +885 -0
  325. data/test/template/form_options_helper_test.rb +1333 -0
  326. data/test/template/form_tag_helper_test.rb +272 -0
  327. data/test/template/javascript_helper_test.rb +73 -0
  328. data/test/template/number_helper_test.rb +97 -0
  329. data/test/template/record_tag_helper_test.rb +54 -0
  330. data/test/template/sanitize_helper_test.rb +48 -0
  331. data/test/template/tag_helper_test.rb +77 -0
  332. data/test/template/template_finder_test.rb +73 -0
  333. data/test/template/template_object_test.rb +95 -0
  334. data/test/template/test_test.rb +56 -0
  335. data/test/template/text_helper_test.rb +367 -0
  336. data/test/template/url_helper_test.rb +544 -0
  337. data/test/testing_sandbox.rb +15 -0
  338. metadata +469 -0
@@ -0,0 +1,458 @@
1
+ require 'cgi'
2
+ require 'action_view/helpers/tag_helper'
3
+
4
+ module ActionView
5
+ module Helpers
6
+ # Provides a number of methods for creating form tags that doesn't rely on an Active Record object assigned to the template like
7
+ # FormHelper does. Instead, you provide the names and values manually.
8
+ #
9
+ # NOTE: The HTML options <tt>disabled</tt>, <tt>readonly</tt>, and <tt>multiple</tt> can all be treated as booleans. So specifying
10
+ # <tt>:disabled => true</tt> will give <tt>disabled="disabled"</tt>.
11
+ module FormTagHelper
12
+ # Starts a form tag that points the action to an url configured with <tt>url_for_options</tt> just like
13
+ # ActionController::Base#url_for. The method for the form defaults to POST.
14
+ #
15
+ # ==== Options
16
+ # * <tt>:multipart</tt> - If set to true, the enctype is set to "multipart/form-data".
17
+ # * <tt>:method</tt> - The method to use when submitting the form, usually either "get" or "post".
18
+ # If "put", "delete", or another verb is used, a hidden input with name <tt>_method</tt>
19
+ # is added to simulate the verb over post.
20
+ # * A list of parameters to feed to the URL the form will be posted to.
21
+ #
22
+ # ==== Examples
23
+ # form_tag('/posts')
24
+ # # => <form action="/posts" method="post">
25
+ #
26
+ # form_tag('/posts/1', :method => :put)
27
+ # # => <form action="/posts/1" method="put">
28
+ #
29
+ # form_tag('/upload', :multipart => true)
30
+ # # => <form action="/upload" method="post" enctype="multipart/form-data">
31
+ #
32
+ # <% form_tag '/posts' do -%>
33
+ # <div><%= submit_tag 'Save' %></div>
34
+ # <% end -%>
35
+ # # => <form action="/posts" method="post"><div><input type="submit" name="submit" value="Save" /></div></form>
36
+ def form_tag(url_for_options = {}, options = {}, *parameters_for_url, &block)
37
+ html_options = html_options_for_form(url_for_options, options, *parameters_for_url)
38
+ if block_given?
39
+ form_tag_in_block(html_options, &block)
40
+ else
41
+ form_tag_html(html_options)
42
+ end
43
+ end
44
+
45
+ # Creates a dropdown selection box, or if the <tt>:multiple</tt> option is set to true, a multiple
46
+ # choice selection box.
47
+ #
48
+ # Helpers::FormOptions can be used to create common select boxes such as countries, time zones, or
49
+ # associated records. <tt>option_tags</tt> is a string containing the option tags for the select box.
50
+ #
51
+ # ==== Options
52
+ # * <tt>:multiple</tt> - If set to true the selection will allow multiple choices.
53
+ # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
54
+ # * Any other key creates standard HTML attributes for the tag.
55
+ #
56
+ # ==== Examples
57
+ # select_tag "people", "<option>David</option>"
58
+ # # => <select id="people" name="people"><option>David</option></select>
59
+ #
60
+ # select_tag "count", "<option>1</option><option>2</option><option>3</option><option>4</option>"
61
+ # # => <select id="count" name="count"><option>1</option><option>2</option>
62
+ # # <option>3</option><option>4</option></select>
63
+ #
64
+ # select_tag "colors", "<option>Red</option><option>Green</option><option>Blue</option>", :multiple => true
65
+ # # => <select id="colors" multiple="multiple" name="colors"><option>Red</option>
66
+ # # <option>Green</option><option>Blue</option></select>
67
+ #
68
+ # select_tag "locations", "<option>Home</option><option selected="selected">Work</option><option>Out</option>"
69
+ # # => <select id="locations" name="locations"><option>Home</option><option selected='selected'>Work</option>
70
+ # # <option>Out</option></select>
71
+ #
72
+ # select_tag "access", "<option>Read</option><option>Write</option>", :multiple => true, :class => 'form_input'
73
+ # # => <select class="form_input" id="access" multiple="multiple" name="access"><option>Read</option>
74
+ # # <option>Write</option></select>
75
+ #
76
+ # select_tag "destination", "<option>NYC</option><option>Paris</option><option>Rome</option>", :disabled => true
77
+ # # => <select disabled="disabled" id="destination" name="destination"><option>NYC</option>
78
+ # # <option>Paris</option><option>Rome</option></select>
79
+ def select_tag(name, option_tags = nil, options = {})
80
+ content_tag :select, option_tags, { "name" => name, "id" => name }.update(options.stringify_keys)
81
+ end
82
+
83
+ # Creates a standard text field; use these text fields to input smaller chunks of text like a username
84
+ # or a search query.
85
+ #
86
+ # ==== Options
87
+ # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
88
+ # * <tt>:size</tt> - The number of visible characters that will fit in the input.
89
+ # * <tt>:maxlength</tt> - The maximum number of characters that the browser will allow the user to enter.
90
+ # * Any other key creates standard HTML attributes for the tag.
91
+ #
92
+ # ==== Examples
93
+ # text_field_tag 'name'
94
+ # # => <input id="name" name="name" type="text" />
95
+ #
96
+ # text_field_tag 'query', 'Enter your search query here'
97
+ # # => <input id="query" name="query" type="text" value="Enter your search query here" />
98
+ #
99
+ # text_field_tag 'request', nil, :class => 'special_input'
100
+ # # => <input class="special_input" id="request" name="request" type="text" />
101
+ #
102
+ # text_field_tag 'address', '', :size => 75
103
+ # # => <input id="address" name="address" size="75" type="text" value="" />
104
+ #
105
+ # text_field_tag 'zip', nil, :maxlength => 5
106
+ # # => <input id="zip" maxlength="5" name="zip" type="text" />
107
+ #
108
+ # text_field_tag 'payment_amount', '$0.00', :disabled => true
109
+ # # => <input disabled="disabled" id="payment_amount" name="payment_amount" type="text" value="$0.00" />
110
+ #
111
+ # text_field_tag 'ip', '0.0.0.0', :maxlength => 15, :size => 20, :class => "ip-input"
112
+ # # => <input class="ip-input" id="ip" maxlength="15" name="ip" size="20" type="text" value="0.0.0.0" />
113
+ def text_field_tag(name, value = nil, options = {})
114
+ tag :input, { "type" => "text", "name" => name, "id" => name, "value" => value }.update(options.stringify_keys)
115
+ end
116
+
117
+ # Creates a label field
118
+ #
119
+ # ==== Options
120
+ # * Creates standard HTML attributes for the tag.
121
+ #
122
+ # ==== Examples
123
+ # label_tag 'name'
124
+ # # => <label for="name">Name</label>
125
+ #
126
+ # label_tag 'name', 'Your name'
127
+ # # => <label for="name">Your Name</label>
128
+ #
129
+ # label_tag 'name', nil, :class => 'small_label'
130
+ # # => <label for="name" class="small_label">Name</label>
131
+ def label_tag(name, text = nil, options = {})
132
+ content_tag :label, text || name.to_s.humanize, { "for" => name }.update(options.stringify_keys)
133
+ end
134
+
135
+ # Creates a hidden form input field used to transmit data that would be lost due to HTTP's statelessness or
136
+ # data that should be hidden from the user.
137
+ #
138
+ # ==== Options
139
+ # * Creates standard HTML attributes for the tag.
140
+ #
141
+ # ==== Examples
142
+ # hidden_field_tag 'tags_list'
143
+ # # => <input id="tags_list" name="tags_list" type="hidden" />
144
+ #
145
+ # hidden_field_tag 'token', 'VUBJKB23UIVI1UU1VOBVI@'
146
+ # # => <input id="token" name="token" type="hidden" value="VUBJKB23UIVI1UU1VOBVI@" />
147
+ #
148
+ # hidden_field_tag 'collected_input', '', :onchange => "alert('Input collected!')"
149
+ # # => <input id="collected_input" name="collected_input" onchange="alert('Input collected!')"
150
+ # # type="hidden" value="" />
151
+ def hidden_field_tag(name, value = nil, options = {})
152
+ text_field_tag(name, value, options.stringify_keys.update("type" => "hidden"))
153
+ end
154
+
155
+ # Creates a file upload field. If you are using file uploads then you will also need
156
+ # to set the multipart option for the form tag:
157
+ #
158
+ # <%= form_tag { :action => "post" }, { :multipart => true } %>
159
+ # <label for="file">File to Upload</label> <%= file_field_tag "file" %>
160
+ # <%= submit_tag %>
161
+ # <%= end_form_tag %>
162
+ #
163
+ # The specified URL will then be passed a File object containing the selected file, or if the field
164
+ # was left blank, a StringIO object.
165
+ #
166
+ # ==== Options
167
+ # * Creates standard HTML attributes for the tag.
168
+ # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
169
+ #
170
+ # ==== Examples
171
+ # file_field_tag 'attachment'
172
+ # # => <input id="attachment" name="attachment" type="file" />
173
+ #
174
+ # file_field_tag 'avatar', :class => 'profile-input'
175
+ # # => <input class="profile-input" id="avatar" name="avatar" type="file" />
176
+ #
177
+ # file_field_tag 'picture', :disabled => true
178
+ # # => <input disabled="disabled" id="picture" name="picture" type="file" />
179
+ #
180
+ # file_field_tag 'resume', :value => '~/resume.doc'
181
+ # # => <input id="resume" name="resume" type="file" value="~/resume.doc" />
182
+ #
183
+ # file_field_tag 'user_pic', :accept => 'image/png,image/gif,image/jpeg'
184
+ # # => <input accept="image/png,image/gif,image/jpeg" id="user_pic" name="user_pic" type="file" />
185
+ #
186
+ # file_field_tag 'file', :accept => 'text/html', :class => 'upload', :value => 'index.html'
187
+ # # => <input accept="text/html" class="upload" id="file" name="file" type="file" value="index.html" />
188
+ def file_field_tag(name, options = {})
189
+ text_field_tag(name, nil, options.update("type" => "file"))
190
+ end
191
+
192
+ # Creates a password field, a masked text field that will hide the users input behind a mask character.
193
+ #
194
+ # ==== Options
195
+ # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
196
+ # * <tt>:size</tt> - The number of visible characters that will fit in the input.
197
+ # * <tt>:maxlength</tt> - The maximum number of characters that the browser will allow the user to enter.
198
+ # * Any other key creates standard HTML attributes for the tag.
199
+ #
200
+ # ==== Examples
201
+ # password_field_tag 'pass'
202
+ # # => <input id="pass" name="pass" type="password" />
203
+ #
204
+ # password_field_tag 'secret', 'Your secret here'
205
+ # # => <input id="secret" name="secret" type="password" value="Your secret here" />
206
+ #
207
+ # password_field_tag 'masked', nil, :class => 'masked_input_field'
208
+ # # => <input class="masked_input_field" id="masked" name="masked" type="password" />
209
+ #
210
+ # password_field_tag 'token', '', :size => 15
211
+ # # => <input id="token" name="token" size="15" type="password" value="" />
212
+ #
213
+ # password_field_tag 'key', nil, :maxlength => 16
214
+ # # => <input id="key" maxlength="16" name="key" type="password" />
215
+ #
216
+ # password_field_tag 'confirm_pass', nil, :disabled => true
217
+ # # => <input disabled="disabled" id="confirm_pass" name="confirm_pass" type="password" />
218
+ #
219
+ # password_field_tag 'pin', '1234', :maxlength => 4, :size => 6, :class => "pin-input"
220
+ # # => <input class="pin-input" id="pin" maxlength="4" name="pin" size="6" type="password" value="1234" />
221
+ def password_field_tag(name = "password", value = nil, options = {})
222
+ text_field_tag(name, value, options.update("type" => "password"))
223
+ end
224
+
225
+ # Creates a text input area; use a textarea for longer text inputs such as blog posts or descriptions.
226
+ #
227
+ # ==== Options
228
+ # * <tt>:size</tt> - A string specifying the dimensions (columns by rows) of the textarea (e.g., "25x10").
229
+ # * <tt>:rows</tt> - Specify the number of rows in the textarea
230
+ # * <tt>:cols</tt> - Specify the number of columns in the textarea
231
+ # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
232
+ # * Any other key creates standard HTML attributes for the tag.
233
+ #
234
+ # ==== Examples
235
+ # text_area_tag 'post'
236
+ # # => <textarea id="post" name="post"></textarea>
237
+ #
238
+ # text_area_tag 'bio', @user.bio
239
+ # # => <textarea id="bio" name="bio">This is my biography.</textarea>
240
+ #
241
+ # text_area_tag 'body', nil, :rows => 10, :cols => 25
242
+ # # => <textarea cols="25" id="body" name="body" rows="10"></textarea>
243
+ #
244
+ # text_area_tag 'body', nil, :size => "25x10"
245
+ # # => <textarea name="body" id="body" cols="25" rows="10"></textarea>
246
+ #
247
+ # text_area_tag 'description', "Description goes here.", :disabled => true
248
+ # # => <textarea disabled="disabled" id="description" name="description">Description goes here.</textarea>
249
+ #
250
+ # text_area_tag 'comment', nil, :class => 'comment_input'
251
+ # # => <textarea class="comment_input" id="comment" name="comment"></textarea>
252
+ def text_area_tag(name, content = nil, options = {})
253
+ options.stringify_keys!
254
+
255
+ if size = options.delete("size")
256
+ options["cols"], options["rows"] = size.split("x") if size.respond_to?(:split)
257
+ end
258
+
259
+ content_tag :textarea, content, { "name" => name, "id" => name }.update(options.stringify_keys)
260
+ end
261
+
262
+ # Creates a check box form input tag.
263
+ #
264
+ # ==== Options
265
+ # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
266
+ # * Any other key creates standard HTML options for the tag.
267
+ #
268
+ # ==== Examples
269
+ # check_box_tag 'accept'
270
+ # # => <input id="accept" name="accept" type="checkbox" value="1" />
271
+ #
272
+ # check_box_tag 'rock', 'rock music'
273
+ # # => <input id="rock" name="rock" type="checkbox" value="rock music" />
274
+ #
275
+ # check_box_tag 'receive_email', 'yes', true
276
+ # # => <input checked="checked" id="receive_email" name="receive_email" type="checkbox" value="yes" />
277
+ #
278
+ # check_box_tag 'tos', 'yes', false, :class => 'accept_tos'
279
+ # # => <input class="accept_tos" id="tos" name="tos" type="checkbox" value="yes" />
280
+ #
281
+ # check_box_tag 'eula', 'accepted', false, :disabled => true
282
+ # # => <input disabled="disabled" id="eula" name="eula" type="checkbox" value="accepted" />
283
+ def check_box_tag(name, value = "1", checked = false, options = {})
284
+ html_options = { "type" => "checkbox", "name" => name, "id" => name, "value" => value }.update(options.stringify_keys)
285
+ html_options["checked"] = "checked" if checked
286
+ tag :input, html_options
287
+ end
288
+
289
+ # Creates a radio button; use groups of radio buttons named the same to allow users to
290
+ # select from a group of options.
291
+ #
292
+ # ==== Options
293
+ # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
294
+ # * Any other key creates standard HTML options for the tag.
295
+ #
296
+ # ==== Examples
297
+ # radio_button_tag 'gender', 'male'
298
+ # # => <input id="gender_male" name="gender" type="radio" value="male" />
299
+ #
300
+ # radio_button_tag 'receive_updates', 'no', true
301
+ # # => <input checked="checked" id="receive_updates_no" name="receive_updates" type="radio" value="no" />
302
+ #
303
+ # radio_button_tag 'time_slot', "3:00 p.m.", false, :disabled => true
304
+ # # => <input disabled="disabled" id="time_slot_300_pm" name="time_slot" type="radio" value="3:00 p.m." />
305
+ #
306
+ # radio_button_tag 'color', "green", true, :class => "color_input"
307
+ # # => <input checked="checked" class="color_input" id="color_green" name="color" type="radio" value="green" />
308
+ def radio_button_tag(name, value, checked = false, options = {})
309
+ pretty_tag_value = value.to_s.gsub(/\s/, "_").gsub(/(?!-)\W/, "").downcase
310
+ pretty_name = name.to_s.gsub(/\[/, "_").gsub(/\]/, "")
311
+ html_options = { "type" => "radio", "name" => name, "id" => "#{pretty_name}_#{pretty_tag_value}", "value" => value }.update(options.stringify_keys)
312
+ html_options["checked"] = "checked" if checked
313
+ tag :input, html_options
314
+ end
315
+
316
+ # Creates a submit button with the text <tt>value</tt> as the caption.
317
+ #
318
+ # ==== Options
319
+ # * <tt>:confirm => 'question?'</tt> - This will add a JavaScript confirm
320
+ # prompt with the question specified. If the user accepts, the form is
321
+ # processed normally, otherwise no action is taken.
322
+ # * <tt>:disabled</tt> - If true, the user will not be able to use this input.
323
+ # * <tt>:disable_with</tt> - Value of this parameter will be used as the value for a disabled version
324
+ # of the submit button when the form is submitted.
325
+ # * Any other key creates standard HTML options for the tag.
326
+ #
327
+ # ==== Examples
328
+ # submit_tag
329
+ # # => <input name="commit" type="submit" value="Save changes" />
330
+ #
331
+ # submit_tag "Edit this article"
332
+ # # => <input name="commit" type="submit" value="Edit this article" />
333
+ #
334
+ # submit_tag "Save edits", :disabled => true
335
+ # # => <input disabled="disabled" name="commit" type="submit" value="Save edits" />
336
+ #
337
+ # submit_tag "Complete sale", :disable_with => "Please wait..."
338
+ # # => <input name="commit" onclick="this.disabled=true;this.value='Please wait...';this.form.submit();"
339
+ # # type="submit" value="Complete sale" />
340
+ #
341
+ # submit_tag nil, :class => "form_submit"
342
+ # # => <input class="form_submit" name="commit" type="submit" />
343
+ #
344
+ # submit_tag "Edit", :disable_with => "Editing...", :class => "edit-button"
345
+ # # => <input class="edit-button" onclick="this.disabled=true;this.value='Editing...';this.form.submit();"
346
+ # # name="commit" type="submit" value="Edit" />
347
+ def submit_tag(value = "Save changes", options = {})
348
+ options.stringify_keys!
349
+
350
+ if disable_with = options.delete("disable_with")
351
+ disable_with = "this.value='#{disable_with}'"
352
+ disable_with << ";#{options.delete('onclick')}" if options['onclick']
353
+
354
+ options["onclick"] = "if (window.hiddenCommit) { window.hiddenCommit.setAttribute('value', this.value); }"
355
+ options["onclick"] << "else { hiddenCommit = this.cloneNode(false);hiddenCommit.setAttribute('type', 'hidden');this.form.appendChild(hiddenCommit); }"
356
+ options["onclick"] << "this.setAttribute('originalValue', this.value);this.disabled = true;#{disable_with};"
357
+ options["onclick"] << "result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());"
358
+ options["onclick"] << "if (result == false) { this.value = this.getAttribute('originalValue');this.disabled = false; }return result;"
359
+ end
360
+
361
+ if confirm = options.delete("confirm")
362
+ options["onclick"] ||= ''
363
+ options["onclick"] << "return #{confirm_javascript_function(confirm)};"
364
+ end
365
+
366
+ tag :input, { "type" => "submit", "name" => "commit", "value" => value }.update(options.stringify_keys)
367
+ end
368
+
369
+ # Displays an image which when clicked will submit the form.
370
+ #
371
+ # <tt>source</tt> is passed to AssetTagHelper#image_path
372
+ #
373
+ # ==== Options
374
+ # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
375
+ # * Any other key creates standard HTML options for the tag.
376
+ #
377
+ # ==== Examples
378
+ # image_submit_tag("login.png")
379
+ # # => <input src="/images/login.png" type="image" />
380
+ #
381
+ # image_submit_tag("purchase.png", :disabled => true)
382
+ # # => <input disabled="disabled" src="/images/purchase.png" type="image" />
383
+ #
384
+ # image_submit_tag("search.png", :class => 'search-button')
385
+ # # => <input class="search-button" src="/images/search.png" type="image" />
386
+ #
387
+ # image_submit_tag("agree.png", :disabled => true, :class => "agree-disagree-button")
388
+ # # => <input class="agree-disagree-button" disabled="disabled" src="/images/agree.png" type="image" />
389
+ def image_submit_tag(source, options = {})
390
+ tag :input, { "type" => "image", "src" => path_to_image(source) }.update(options.stringify_keys)
391
+ end
392
+
393
+ # Creates a field set for grouping HTML form elements.
394
+ #
395
+ # <tt>legend</tt> will become the fieldset's title (optional as per W3C).
396
+ #
397
+ # === Examples
398
+ # <% field_set_tag do %>
399
+ # <p><%= text_field_tag 'name' %></p>
400
+ # <% end %>
401
+ # # => <fieldset><p><input id="name" name="name" type="text" /></p></fieldset>
402
+ #
403
+ # <% field_set_tag 'Your details' do %>
404
+ # <p><%= text_field_tag 'name' %></p>
405
+ # <% end %>
406
+ # # => <fieldset><legend>Your details</legend><p><input id="name" name="name" type="text" /></p></fieldset>
407
+ def field_set_tag(legend = nil, &block)
408
+ content = capture(&block)
409
+ concat(tag(:fieldset, {}, true), block.binding)
410
+ concat(content_tag(:legend, legend), block.binding) unless legend.blank?
411
+ concat(content, block.binding)
412
+ concat("</fieldset>", block.binding)
413
+ end
414
+
415
+ private
416
+ def html_options_for_form(url_for_options, options, *parameters_for_url)
417
+ returning options.stringify_keys do |html_options|
418
+ html_options["enctype"] = "multipart/form-data" if html_options.delete("multipart")
419
+ html_options["action"] = url_for(url_for_options, *parameters_for_url)
420
+ end
421
+ end
422
+
423
+ def extra_tags_for_form(html_options)
424
+ case method = html_options.delete("method").to_s
425
+ when /^get$/i # must be case-insentive, but can't use downcase as might be nil
426
+ html_options["method"] = "get"
427
+ ''
428
+ when /^post$/i, "", nil
429
+ html_options["method"] = "post"
430
+ protect_against_forgery? ? content_tag(:div, token_tag, :style => 'margin:0;padding:0') : ''
431
+ else
432
+ html_options["method"] = "post"
433
+ content_tag(:div, tag(:input, :type => "hidden", :name => "_method", :value => method) + token_tag, :style => 'margin:0;padding:0')
434
+ end
435
+ end
436
+
437
+ def form_tag_html(html_options)
438
+ extra_tags = extra_tags_for_form(html_options)
439
+ tag(:form, html_options, true) + extra_tags
440
+ end
441
+
442
+ def form_tag_in_block(html_options, &block)
443
+ content = capture(&block)
444
+ concat(form_tag_html(html_options), block.binding)
445
+ concat(content, block.binding)
446
+ concat("</form>", block.binding)
447
+ end
448
+
449
+ def token_tag
450
+ unless protect_against_forgery?
451
+ ''
452
+ else
453
+ tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token)
454
+ end
455
+ end
456
+ end
457
+ end
458
+ end