actionpack 3.2.22.5 → 5.2.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (271) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +279 -603
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +13 -297
  5. data/lib/abstract_controller/asset_paths.rb +4 -2
  6. data/lib/abstract_controller/base.rb +82 -52
  7. data/lib/abstract_controller/caching/fragments.rb +166 -0
  8. data/lib/abstract_controller/caching.rb +66 -0
  9. data/lib/abstract_controller/callbacks.rb +117 -103
  10. data/lib/abstract_controller/collector.rb +18 -7
  11. data/lib/abstract_controller/error.rb +6 -0
  12. data/lib/abstract_controller/helpers.rb +65 -38
  13. data/lib/abstract_controller/logger.rb +3 -2
  14. data/lib/abstract_controller/railties/routes_helpers.rb +5 -3
  15. data/lib/abstract_controller/rendering.rb +77 -129
  16. data/lib/abstract_controller/translation.rb +21 -3
  17. data/lib/abstract_controller/url_for.rb +9 -7
  18. data/lib/abstract_controller.rb +12 -13
  19. data/lib/action_controller/api/api_rendering.rb +16 -0
  20. data/lib/action_controller/api.rb +149 -0
  21. data/lib/action_controller/base.rb +81 -40
  22. data/lib/action_controller/caching.rb +22 -62
  23. data/lib/action_controller/form_builder.rb +50 -0
  24. data/lib/action_controller/log_subscriber.rb +30 -18
  25. data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
  26. data/lib/action_controller/metal/conditional_get.rb +190 -47
  27. data/lib/action_controller/metal/content_security_policy.rb +52 -0
  28. data/lib/action_controller/metal/cookies.rb +3 -3
  29. data/lib/action_controller/metal/data_streaming.rb +40 -65
  30. data/lib/action_controller/metal/etag_with_flash.rb +18 -0
  31. data/lib/action_controller/metal/etag_with_template_digest.rb +57 -0
  32. data/lib/action_controller/metal/exceptions.rb +19 -12
  33. data/lib/action_controller/metal/flash.rb +42 -9
  34. data/lib/action_controller/metal/force_ssl.rb +79 -19
  35. data/lib/action_controller/metal/head.rb +35 -10
  36. data/lib/action_controller/metal/helpers.rb +31 -21
  37. data/lib/action_controller/metal/http_authentication.rb +182 -134
  38. data/lib/action_controller/metal/implicit_render.rb +62 -8
  39. data/lib/action_controller/metal/instrumentation.rb +28 -26
  40. data/lib/action_controller/metal/live.rb +312 -0
  41. data/lib/action_controller/metal/mime_responds.rb +159 -163
  42. data/lib/action_controller/metal/parameter_encoding.rb +51 -0
  43. data/lib/action_controller/metal/params_wrapper.rb +146 -93
  44. data/lib/action_controller/metal/redirecting.rb +80 -56
  45. data/lib/action_controller/metal/renderers.rb +119 -47
  46. data/lib/action_controller/metal/rendering.rb +89 -32
  47. data/lib/action_controller/metal/request_forgery_protection.rb +373 -41
  48. data/lib/action_controller/metal/rescue.rb +9 -16
  49. data/lib/action_controller/metal/streaming.rb +39 -45
  50. data/lib/action_controller/metal/strong_parameters.rb +1086 -0
  51. data/lib/action_controller/metal/testing.rb +8 -29
  52. data/lib/action_controller/metal/url_for.rb +43 -32
  53. data/lib/action_controller/metal.rb +112 -106
  54. data/lib/action_controller/railtie.rb +56 -18
  55. data/lib/action_controller/railties/helpers.rb +24 -0
  56. data/lib/action_controller/renderer.rb +117 -0
  57. data/lib/action_controller/template_assertions.rb +11 -0
  58. data/lib/action_controller/test_case.rb +402 -347
  59. data/lib/action_controller.rb +31 -30
  60. data/lib/action_dispatch/http/cache.rb +133 -34
  61. data/lib/action_dispatch/http/content_security_policy.rb +272 -0
  62. data/lib/action_dispatch/http/filter_parameters.rb +40 -24
  63. data/lib/action_dispatch/http/filter_redirect.rb +37 -0
  64. data/lib/action_dispatch/http/headers.rb +117 -16
  65. data/lib/action_dispatch/http/mime_negotiation.rb +98 -33
  66. data/lib/action_dispatch/http/mime_type.rb +198 -146
  67. data/lib/action_dispatch/http/mime_types.rb +22 -7
  68. data/lib/action_dispatch/http/parameter_filter.rb +61 -49
  69. data/lib/action_dispatch/http/parameters.rb +94 -51
  70. data/lib/action_dispatch/http/rack_cache.rb +4 -3
  71. data/lib/action_dispatch/http/request.rb +262 -117
  72. data/lib/action_dispatch/http/response.rb +400 -86
  73. data/lib/action_dispatch/http/upload.rb +66 -29
  74. data/lib/action_dispatch/http/url.rb +232 -60
  75. data/lib/action_dispatch/journey/formatter.rb +189 -0
  76. data/lib/action_dispatch/journey/gtg/builder.rb +164 -0
  77. data/lib/action_dispatch/journey/gtg/simulator.rb +41 -0
  78. data/lib/action_dispatch/journey/gtg/transition_table.rb +158 -0
  79. data/lib/action_dispatch/journey/nfa/builder.rb +78 -0
  80. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  81. data/lib/action_dispatch/journey/nfa/simulator.rb +49 -0
  82. data/lib/action_dispatch/journey/nfa/transition_table.rb +120 -0
  83. data/lib/action_dispatch/journey/nodes/node.rb +140 -0
  84. data/lib/action_dispatch/journey/parser.rb +199 -0
  85. data/lib/action_dispatch/journey/parser.y +50 -0
  86. data/lib/action_dispatch/journey/parser_extras.rb +31 -0
  87. data/lib/action_dispatch/journey/path/pattern.rb +199 -0
  88. data/lib/action_dispatch/journey/route.rb +203 -0
  89. data/lib/action_dispatch/journey/router/utils.rb +102 -0
  90. data/lib/action_dispatch/journey/router.rb +156 -0
  91. data/lib/action_dispatch/journey/routes.rb +82 -0
  92. data/lib/action_dispatch/journey/scanner.rb +64 -0
  93. data/lib/action_dispatch/journey/visitors.rb +268 -0
  94. data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
  95. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  96. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  97. data/lib/action_dispatch/journey.rb +7 -0
  98. data/lib/action_dispatch/middleware/callbacks.rb +17 -13
  99. data/lib/action_dispatch/middleware/cookies.rb +494 -162
  100. data/lib/action_dispatch/middleware/debug_exceptions.rb +176 -53
  101. data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
  102. data/lib/action_dispatch/middleware/exception_wrapper.rb +103 -38
  103. data/lib/action_dispatch/middleware/executor.rb +21 -0
  104. data/lib/action_dispatch/middleware/flash.rb +128 -91
  105. data/lib/action_dispatch/middleware/public_exceptions.rb +43 -16
  106. data/lib/action_dispatch/middleware/reloader.rb +6 -83
  107. data/lib/action_dispatch/middleware/remote_ip.rb +151 -49
  108. data/lib/action_dispatch/middleware/request_id.rb +19 -15
  109. data/lib/action_dispatch/middleware/session/abstract_store.rb +38 -34
  110. data/lib/action_dispatch/middleware/session/cache_store.rb +14 -9
  111. data/lib/action_dispatch/middleware/session/cookie_store.rb +94 -44
  112. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +15 -4
  113. data/lib/action_dispatch/middleware/show_exceptions.rb +36 -61
  114. data/lib/action_dispatch/middleware/ssl.rb +150 -0
  115. data/lib/action_dispatch/middleware/stack.rb +33 -41
  116. data/lib/action_dispatch/middleware/static.rb +92 -48
  117. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +22 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  119. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +27 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  121. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
  122. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  123. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +16 -0
  124. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  125. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +21 -0
  126. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +13 -0
  127. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +134 -5
  128. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  129. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  130. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
  131. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  132. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  133. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  134. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
  135. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  136. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  137. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +200 -0
  138. data/lib/action_dispatch/railtie.rb +29 -8
  139. data/lib/action_dispatch/request/session.rb +234 -0
  140. data/lib/action_dispatch/request/utils.rb +78 -0
  141. data/lib/action_dispatch/routing/endpoint.rb +17 -0
  142. data/lib/action_dispatch/routing/inspector.rb +225 -0
  143. data/lib/action_dispatch/routing/mapper.rb +1329 -582
  144. data/lib/action_dispatch/routing/polymorphic_routes.rb +237 -94
  145. data/lib/action_dispatch/routing/redirection.rb +120 -50
  146. data/lib/action_dispatch/routing/route_set.rb +545 -322
  147. data/lib/action_dispatch/routing/routes_proxy.rb +37 -7
  148. data/lib/action_dispatch/routing/url_for.rb +103 -34
  149. data/lib/action_dispatch/routing.rb +66 -99
  150. data/lib/action_dispatch/system_test_case.rb +147 -0
  151. data/lib/action_dispatch/system_testing/browser.rb +49 -0
  152. data/lib/action_dispatch/system_testing/driver.rb +59 -0
  153. data/lib/action_dispatch/system_testing/server.rb +31 -0
  154. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +96 -0
  155. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +31 -0
  156. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +26 -0
  157. data/lib/action_dispatch/testing/assertion_response.rb +47 -0
  158. data/lib/action_dispatch/testing/assertions/response.rb +53 -42
  159. data/lib/action_dispatch/testing/assertions/routing.rb +79 -74
  160. data/lib/action_dispatch/testing/assertions.rb +15 -9
  161. data/lib/action_dispatch/testing/integration.rb +361 -207
  162. data/lib/action_dispatch/testing/request_encoder.rb +55 -0
  163. data/lib/action_dispatch/testing/test_process.rb +28 -19
  164. data/lib/action_dispatch/testing/test_request.rb +30 -33
  165. data/lib/action_dispatch/testing/test_response.rb +35 -11
  166. data/lib/action_dispatch.rb +42 -32
  167. data/lib/action_pack/gem_version.rb +17 -0
  168. data/lib/action_pack/version.rb +7 -7
  169. data/lib/action_pack.rb +4 -2
  170. metadata +116 -175
  171. data/lib/abstract_controller/layouts.rb +0 -423
  172. data/lib/abstract_controller/view_paths.rb +0 -96
  173. data/lib/action_controller/caching/actions.rb +0 -185
  174. data/lib/action_controller/caching/fragments.rb +0 -127
  175. data/lib/action_controller/caching/pages.rb +0 -187
  176. data/lib/action_controller/caching/sweeping.rb +0 -97
  177. data/lib/action_controller/deprecated/integration_test.rb +0 -2
  178. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  179. data/lib/action_controller/deprecated.rb +0 -3
  180. data/lib/action_controller/metal/compatibility.rb +0 -65
  181. data/lib/action_controller/metal/hide_actions.rb +0 -41
  182. data/lib/action_controller/metal/rack_delegation.rb +0 -26
  183. data/lib/action_controller/metal/responder.rb +0 -286
  184. data/lib/action_controller/metal/session_management.rb +0 -14
  185. data/lib/action_controller/middleware.rb +0 -39
  186. data/lib/action_controller/railties/paths.rb +0 -25
  187. data/lib/action_controller/record_identifier.rb +0 -85
  188. data/lib/action_controller/vendor/html-scanner/html/document.rb +0 -68
  189. data/lib/action_controller/vendor/html-scanner/html/node.rb +0 -532
  190. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +0 -177
  191. data/lib/action_controller/vendor/html-scanner/html/selector.rb +0 -830
  192. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +0 -107
  193. data/lib/action_controller/vendor/html-scanner/html/version.rb +0 -11
  194. data/lib/action_controller/vendor/html-scanner.rb +0 -20
  195. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  196. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  197. data/lib/action_dispatch/middleware/head.rb +0 -18
  198. data/lib/action_dispatch/middleware/params_parser.rb +0 -75
  199. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  200. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +0 -31
  201. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +0 -26
  202. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +0 -10
  203. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +0 -2
  204. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +0 -15
  205. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +0 -17
  206. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +0 -2
  207. data/lib/action_dispatch/testing/assertions/dom.rb +0 -37
  208. data/lib/action_dispatch/testing/assertions/selector.rb +0 -435
  209. data/lib/action_dispatch/testing/assertions/tag.rb +0 -138
  210. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  211. data/lib/action_view/asset_paths.rb +0 -142
  212. data/lib/action_view/base.rb +0 -220
  213. data/lib/action_view/buffers.rb +0 -43
  214. data/lib/action_view/context.rb +0 -36
  215. data/lib/action_view/flows.rb +0 -79
  216. data/lib/action_view/helpers/active_model_helper.rb +0 -50
  217. data/lib/action_view/helpers/asset_paths.rb +0 -7
  218. data/lib/action_view/helpers/asset_tag_helper.rb +0 -457
  219. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  220. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  221. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  222. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  223. data/lib/action_view/helpers/atom_feed_helper.rb +0 -200
  224. data/lib/action_view/helpers/cache_helper.rb +0 -64
  225. data/lib/action_view/helpers/capture_helper.rb +0 -203
  226. data/lib/action_view/helpers/controller_helper.rb +0 -25
  227. data/lib/action_view/helpers/csrf_helper.rb +0 -32
  228. data/lib/action_view/helpers/date_helper.rb +0 -1062
  229. data/lib/action_view/helpers/debug_helper.rb +0 -40
  230. data/lib/action_view/helpers/form_helper.rb +0 -1486
  231. data/lib/action_view/helpers/form_options_helper.rb +0 -658
  232. data/lib/action_view/helpers/form_tag_helper.rb +0 -685
  233. data/lib/action_view/helpers/javascript_helper.rb +0 -110
  234. data/lib/action_view/helpers/number_helper.rb +0 -622
  235. data/lib/action_view/helpers/output_safety_helper.rb +0 -38
  236. data/lib/action_view/helpers/record_tag_helper.rb +0 -111
  237. data/lib/action_view/helpers/rendering_helper.rb +0 -92
  238. data/lib/action_view/helpers/sanitize_helper.rb +0 -259
  239. data/lib/action_view/helpers/tag_helper.rb +0 -167
  240. data/lib/action_view/helpers/text_helper.rb +0 -426
  241. data/lib/action_view/helpers/translation_helper.rb +0 -91
  242. data/lib/action_view/helpers/url_helper.rb +0 -693
  243. data/lib/action_view/helpers.rb +0 -60
  244. data/lib/action_view/locale/en.yml +0 -160
  245. data/lib/action_view/log_subscriber.rb +0 -28
  246. data/lib/action_view/lookup_context.rb +0 -258
  247. data/lib/action_view/path_set.rb +0 -101
  248. data/lib/action_view/railtie.rb +0 -55
  249. data/lib/action_view/renderer/abstract_renderer.rb +0 -41
  250. data/lib/action_view/renderer/partial_renderer.rb +0 -415
  251. data/lib/action_view/renderer/renderer.rb +0 -61
  252. data/lib/action_view/renderer/streaming_template_renderer.rb +0 -106
  253. data/lib/action_view/renderer/template_renderer.rb +0 -95
  254. data/lib/action_view/template/error.rb +0 -128
  255. data/lib/action_view/template/handlers/builder.rb +0 -26
  256. data/lib/action_view/template/handlers/erb.rb +0 -125
  257. data/lib/action_view/template/handlers.rb +0 -50
  258. data/lib/action_view/template/resolver.rb +0 -298
  259. data/lib/action_view/template/text.rb +0 -30
  260. data/lib/action_view/template.rb +0 -337
  261. data/lib/action_view/test_case.rb +0 -246
  262. data/lib/action_view/testing/resolvers.rb +0 -49
  263. data/lib/action_view.rb +0 -84
  264. data/lib/sprockets/assets.rake +0 -99
  265. data/lib/sprockets/bootstrap.rb +0 -37
  266. data/lib/sprockets/compressors.rb +0 -83
  267. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  268. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  269. data/lib/sprockets/helpers.rb +0 -6
  270. data/lib/sprockets/railtie.rb +0 -62
  271. data/lib/sprockets/static_compiler.rb +0 -56
@@ -1,658 +0,0 @@
1
- require 'cgi'
2
- require 'erb'
3
- require 'action_view/helpers/form_helper'
4
- require 'active_support/core_ext/object/blank'
5
- require 'active_support/core_ext/string/output_safety'
6
-
7
- module ActionView
8
- # = Action View Form Option Helpers
9
- module Helpers
10
- # Provides a number of methods for turning different kinds of containers into a set of option tags.
11
- # == Options
12
- # The <tt>collection_select</tt>, <tt>select</tt> and <tt>time_zone_select</tt> methods take an <tt>options</tt> parameter, a hash:
13
- #
14
- # * <tt>:include_blank</tt> - set to true or a prompt string if the first option element of the select element is a blank. Useful if there is not a default value required for the select element.
15
- #
16
- # For example,
17
- #
18
- # select("post", "category", Post::CATEGORIES, {:include_blank => true})
19
- #
20
- # could become:
21
- #
22
- # <select name="post[category]">
23
- # <option></option>
24
- # <option>joke</option>
25
- # <option>poem</option>
26
- # </select>
27
- #
28
- # Another common case is a select tag for an <tt>belongs_to</tt>-associated object.
29
- #
30
- # Example with @post.person_id => 2:
31
- #
32
- # select("post", "person_id", Person.all.collect {|p| [ p.name, p.id ] }, {:include_blank => 'None'})
33
- #
34
- # could become:
35
- #
36
- # <select name="post[person_id]">
37
- # <option value="">None</option>
38
- # <option value="1">David</option>
39
- # <option value="2" selected="selected">Sam</option>
40
- # <option value="3">Tobias</option>
41
- # </select>
42
- #
43
- # * <tt>:prompt</tt> - set to true or a prompt string. When the select element doesn't have a value yet, this prepends an option with a generic prompt -- "Please select" -- or the given prompt string.
44
- #
45
- # Example:
46
- #
47
- # select("post", "person_id", Person.all.collect {|p| [ p.name, p.id ] }, {:prompt => 'Select Person'})
48
- #
49
- # could become:
50
- #
51
- # <select name="post[person_id]">
52
- # <option value="">Select Person</option>
53
- # <option value="1">David</option>
54
- # <option value="2">Sam</option>
55
- # <option value="3">Tobias</option>
56
- # </select>
57
- #
58
- # Like the other form helpers, +select+ can accept an <tt>:index</tt> option to manually set the ID used in the resulting output. Unlike other helpers, +select+ expects this
59
- # option to be in the +html_options+ parameter.
60
- #
61
- # Example:
62
- #
63
- # select("album[]", "genre", %w[rap rock country], {}, { :index => nil })
64
- #
65
- # becomes:
66
- #
67
- # <select name="album[][genre]" id="album__genre">
68
- # <option value="rap">rap</option>
69
- # <option value="rock">rock</option>
70
- # <option value="country">country</option>
71
- # </select>
72
- #
73
- # * <tt>:disabled</tt> - can be a single value or an array of values that will be disabled options in the final output.
74
- #
75
- # Example:
76
- #
77
- # select("post", "category", Post::CATEGORIES, {:disabled => 'restricted'})
78
- #
79
- # could become:
80
- #
81
- # <select name="post[category]">
82
- # <option></option>
83
- # <option>joke</option>
84
- # <option>poem</option>
85
- # <option disabled="disabled">restricted</option>
86
- # </select>
87
- #
88
- # When used with the <tt>collection_select</tt> helper, <tt>:disabled</tt> can also be a Proc that identifies those options that should be disabled.
89
- #
90
- # Example:
91
- #
92
- # collection_select(:post, :category_id, Category.all, :id, :name, {:disabled => lambda{|category| category.archived? }})
93
- #
94
- # If the categories "2008 stuff" and "Christmas" return true when the method <tt>archived?</tt> is called, this would return:
95
- # <select name="post[category_id]">
96
- # <option value="1" disabled="disabled">2008 stuff</option>
97
- # <option value="2" disabled="disabled">Christmas</option>
98
- # <option value="3">Jokes</option>
99
- # <option value="4">Poems</option>
100
- # </select>
101
- #
102
- module FormOptionsHelper
103
- # ERB::Util can mask some helpers like textilize. Make sure to include them.
104
- include TextHelper
105
-
106
- # Create a select tag and a series of contained option tags for the provided object and method.
107
- # The option currently held by the object will be selected, provided that the object is available.
108
- #
109
- # There are two possible formats for the choices parameter, corresponding to other helpers' output:
110
- # * A flat collection: see options_for_select
111
- # * A nested collection: see grouped_options_for_select
112
- #
113
- # Example with @post.person_id => 1:
114
- # select("post", "person_id", Person.all.collect {|p| [ p.name, p.id ] }, { :include_blank => true })
115
- #
116
- # could become:
117
- #
118
- # <select name="post[person_id]">
119
- # <option value=""></option>
120
- # <option value="1" selected="selected">David</option>
121
- # <option value="2">Sam</option>
122
- # <option value="3">Tobias</option>
123
- # </select>
124
- #
125
- # This can be used to provide a default set of options in the standard way: before rendering the create form, a
126
- # new model instance is assigned the default options and bound to @model_name. Usually this model is not saved
127
- # to the database. Instead, a second model object is created when the create request is received.
128
- # This allows the user to submit a form page more than once with the expected results of creating multiple records.
129
- # In addition, this allows a single partial to be used to generate form inputs for both edit and create forms.
130
- #
131
- # By default, <tt>post.person_id</tt> is the selected option. Specify <tt>:selected => value</tt> to use a different selection
132
- # or <tt>:selected => nil</tt> to leave all options unselected. Similarly, you can specify values to be disabled in the option
133
- # tags by specifying the <tt>:disabled</tt> option. This can either be a single value or an array of values to be disabled.
134
- #
135
- # ==== Gotcha
136
- #
137
- # The HTML specification says when +multiple+ parameter passed to select and all options got deselected
138
- # web browsers do not send any value to server. Unfortunately this introduces a gotcha:
139
- # if an +User+ model has many +roles+ and have +role_ids+ accessor, and in the form that edits roles of the user
140
- # the user deselects all roles from +role_ids+ multiple select box, no +role_ids+ parameter is sent. So,
141
- # any mass-assignment idiom like
142
- #
143
- # @user.update_attributes(params[:user])
144
- #
145
- # wouldn't update roles.
146
- #
147
- # To prevent this the helper generates an auxiliary hidden field before
148
- # every multiple select. The hidden field has the same name as multiple select and blank value.
149
- #
150
- # This way, the client either sends only the hidden field (representing
151
- # the deselected multiple select box), or both fields. Since the HTML specification
152
- # says key/value pairs have to be sent in the same order they appear in the
153
- # form, and parameters extraction gets the last occurrence of any repeated
154
- # key in the query string, that works for ordinary forms.
155
- #
156
- def select(object, method, choices, options = {}, html_options = {})
157
- InstanceTag.new(object, method, self, options.delete(:object)).to_select_tag(choices, options, html_options)
158
- end
159
-
160
- # Returns <tt><select></tt> and <tt><option></tt> tags for the collection of existing return values of
161
- # +method+ for +object+'s class. The value returned from calling +method+ on the instance +object+ will
162
- # be selected. If calling +method+ returns +nil+, no selection is made without including <tt>:prompt</tt>
163
- # or <tt>:include_blank</tt> in the +options+ hash.
164
- #
165
- # The <tt>:value_method</tt> and <tt>:text_method</tt> parameters are methods to be called on each member
166
- # of +collection+. The return values are used as the +value+ attribute and contents of each
167
- # <tt><option></tt> tag, respectively.
168
- #
169
- # Example object structure for use with this method:
170
- # class Post < ActiveRecord::Base
171
- # belongs_to :author
172
- # end
173
- # class Author < ActiveRecord::Base
174
- # has_many :posts
175
- # def name_with_initial
176
- # "#{first_name.first}. #{last_name}"
177
- # end
178
- # end
179
- #
180
- # Sample usage (selecting the associated Author for an instance of Post, <tt>@post</tt>):
181
- # collection_select(:post, :author_id, Author.all, :id, :name_with_initial, :prompt => true)
182
- #
183
- # If <tt>@post.author_id</tt> is already <tt>1</tt>, this would return:
184
- # <select name="post[author_id]">
185
- # <option value="">Please select</option>
186
- # <option value="1" selected="selected">D. Heinemeier Hansson</option>
187
- # <option value="2">D. Thomas</option>
188
- # <option value="3">M. Clark</option>
189
- # </select>
190
- def collection_select(object, method, collection, value_method, text_method, options = {}, html_options = {})
191
- InstanceTag.new(object, method, self, options.delete(:object)).to_collection_select_tag(collection, value_method, text_method, options, html_options)
192
- end
193
-
194
-
195
- # Returns <tt><select></tt>, <tt><optgroup></tt> and <tt><option></tt> tags for the collection of existing return values of
196
- # +method+ for +object+'s class. The value returned from calling +method+ on the instance +object+ will
197
- # be selected. If calling +method+ returns +nil+, no selection is made without including <tt>:prompt</tt>
198
- # or <tt>:include_blank</tt> in the +options+ hash.
199
- #
200
- # Parameters:
201
- # * +object+ - The instance of the class to be used for the select tag
202
- # * +method+ - The attribute of +object+ corresponding to the select tag
203
- # * +collection+ - An array of objects representing the <tt><optgroup></tt> tags.
204
- # * +group_method+ - The name of a method which, when called on a member of +collection+, returns an
205
- # array of child objects representing the <tt><option></tt> tags.
206
- # * +group_label_method+ - The name of a method which, when called on a member of +collection+, returns a
207
- # string to be used as the +label+ attribute for its <tt><optgroup></tt> tag.
208
- # * +option_key_method+ - The name of a method which, when called on a child object of a member of
209
- # +collection+, returns a value to be used as the +value+ attribute for its <tt><option></tt> tag.
210
- # * +option_value_method+ - The name of a method which, when called on a child object of a member of
211
- # +collection+, returns a value to be used as the contents of its <tt><option></tt> tag.
212
- #
213
- # Example object structure for use with this method:
214
- # class Continent < ActiveRecord::Base
215
- # has_many :countries
216
- # # attribs: id, name
217
- # end
218
- # class Country < ActiveRecord::Base
219
- # belongs_to :continent
220
- # # attribs: id, name, continent_id
221
- # end
222
- # class City < ActiveRecord::Base
223
- # belongs_to :country
224
- # # attribs: id, name, country_id
225
- # end
226
- #
227
- # Sample usage:
228
- # grouped_collection_select(:city, :country_id, @continents, :countries, :name, :id, :name)
229
- #
230
- # Possible output:
231
- # <select name="city[country_id]">
232
- # <optgroup label="Africa">
233
- # <option value="1">South Africa</option>
234
- # <option value="3">Somalia</option>
235
- # </optgroup>
236
- # <optgroup label="Europe">
237
- # <option value="7" selected="selected">Denmark</option>
238
- # <option value="2">Ireland</option>
239
- # </optgroup>
240
- # </select>
241
- #
242
- def grouped_collection_select(object, method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {})
243
- InstanceTag.new(object, method, self, options.delete(:object)).to_grouped_collection_select_tag(collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options)
244
- end
245
-
246
- # Return select and option tags for the given object and method, using
247
- # #time_zone_options_for_select to generate the list of option tags.
248
- #
249
- # In addition to the <tt>:include_blank</tt> option documented above,
250
- # this method also supports a <tt>:model</tt> option, which defaults
251
- # to ActiveSupport::TimeZone. This may be used by users to specify a
252
- # different time zone model object. (See +time_zone_options_for_select+
253
- # for more information.)
254
- #
255
- # You can also supply an array of ActiveSupport::TimeZone objects
256
- # as +priority_zones+, so that they will be listed above the rest of the
257
- # (long) list. (You can use ActiveSupport::TimeZone.us_zones as a convenience
258
- # for obtaining a list of the US time zones, or a Regexp to select the zones
259
- # of your choice)
260
- #
261
- # Finally, this method supports a <tt>:default</tt> option, which selects
262
- # a default ActiveSupport::TimeZone if the object's time zone is +nil+.
263
- #
264
- # Examples:
265
- # time_zone_select( "user", "time_zone", nil, :include_blank => true)
266
- #
267
- # time_zone_select( "user", "time_zone", nil, :default => "Pacific Time (US & Canada)" )
268
- #
269
- # time_zone_select( "user", 'time_zone', ActiveSupport::TimeZone.us_zones, :default => "Pacific Time (US & Canada)")
270
- #
271
- # time_zone_select( "user", 'time_zone', [ ActiveSupport::TimeZone['Alaska'], ActiveSupport::TimeZone['Hawaii'] ])
272
- #
273
- # time_zone_select( "user", 'time_zone', /Australia/)
274
- #
275
- # time_zone_select( "user", "time_zone", ActiveSupport::TimeZone.all.sort, :model => ActiveSupport::TimeZone)
276
- def time_zone_select(object, method, priority_zones = nil, options = {}, html_options = {})
277
- InstanceTag.new(object, method, self, options.delete(:object)).to_time_zone_select_tag(priority_zones, options, html_options)
278
- end
279
-
280
- # Accepts a container (hash, array, enumerable, your type) and returns a string of option tags. Given a container
281
- # where the elements respond to first and last (such as a two-element array), the "lasts" serve as option values and
282
- # the "firsts" as option text. Hashes are turned into this form automatically, so the keys become "firsts" and values
283
- # become lasts. If +selected+ is specified, the matching "last" or element will get the selected option-tag. +selected+
284
- # may also be an array of values to be selected when using a multiple select.
285
- #
286
- # Examples (call, result):
287
- # options_for_select([["Dollar", "$"], ["Kroner", "DKK"]])
288
- # <option value="$">Dollar</option>\n<option value="DKK">Kroner</option>
289
- #
290
- # options_for_select([ "VISA", "MasterCard" ], "MasterCard")
291
- # <option>VISA</option>\n<option selected="selected">MasterCard</option>
292
- #
293
- # options_for_select({ "Basic" => "$20", "Plus" => "$40" }, "$40")
294
- # <option value="$20">Basic</option>\n<option value="$40" selected="selected">Plus</option>
295
- #
296
- # options_for_select([ "VISA", "MasterCard", "Discover" ], ["VISA", "Discover"])
297
- # <option selected="selected">VISA</option>\n<option>MasterCard</option>\n<option selected="selected">Discover</option>
298
- #
299
- # You can optionally provide html attributes as the last element of the array.
300
- #
301
- # Examples:
302
- # options_for_select([ "Denmark", ["USA", {:class => 'bold'}], "Sweden" ], ["USA", "Sweden"])
303
- # <option value="Denmark">Denmark</option>\n<option value="USA" class="bold" selected="selected">USA</option>\n<option value="Sweden" selected="selected">Sweden</option>
304
- #
305
- # options_for_select([["Dollar", "$", {:class => "bold"}], ["Kroner", "DKK", {:onclick => "alert('HI');"}]])
306
- # <option value="$" class="bold">Dollar</option>\n<option value="DKK" onclick="alert('HI');">Kroner</option>
307
- #
308
- # If you wish to specify disabled option tags, set +selected+ to be a hash, with <tt>:disabled</tt> being either a value
309
- # or array of values to be disabled. In this case, you can use <tt>:selected</tt> to specify selected option tags.
310
- #
311
- # Examples:
312
- # options_for_select(["Free", "Basic", "Advanced", "Super Platinum"], :disabled => "Super Platinum")
313
- # <option value="Free">Free</option>\n<option value="Basic">Basic</option>\n<option value="Advanced">Advanced</option>\n<option value="Super Platinum" disabled="disabled">Super Platinum</option>
314
- #
315
- # options_for_select(["Free", "Basic", "Advanced", "Super Platinum"], :disabled => ["Advanced", "Super Platinum"])
316
- # <option value="Free">Free</option>\n<option value="Basic">Basic</option>\n<option value="Advanced" disabled="disabled">Advanced</option>\n<option value="Super Platinum" disabled="disabled">Super Platinum</option>
317
- #
318
- # options_for_select(["Free", "Basic", "Advanced", "Super Platinum"], :selected => "Free", :disabled => "Super Platinum")
319
- # <option value="Free" selected="selected">Free</option>\n<option value="Basic">Basic</option>\n<option value="Advanced">Advanced</option>\n<option value="Super Platinum" disabled="disabled">Super Platinum</option>
320
- #
321
- # NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag.
322
- def options_for_select(container, selected = nil)
323
- return container if String === container
324
-
325
- selected, disabled = extract_selected_and_disabled(selected).map do | r |
326
- Array.wrap(r).map { |item| item.to_s }
327
- end
328
-
329
- container.map do |element|
330
- html_attributes = option_html_attributes(element)
331
- text, value = option_text_and_value(element).map { |item| item.to_s }
332
- selected_attribute = ' selected="selected"' if option_value_selected?(value, selected)
333
- disabled_attribute = ' disabled="disabled"' if disabled && option_value_selected?(value, disabled)
334
- %(<option value="#{ERB::Util.html_escape(value)}"#{selected_attribute}#{disabled_attribute}#{html_attributes}>#{ERB::Util.html_escape(text)}</option>)
335
- end.join("\n").html_safe
336
-
337
- end
338
-
339
- # Returns a string of option tags that have been compiled by iterating over the +collection+ and assigning
340
- # the result of a call to the +value_method+ as the option value and the +text_method+ as the option text.
341
- # Example:
342
- # options_from_collection_for_select(@people, 'id', 'name')
343
- # This will output the same HTML as if you did this:
344
- # <option value="#{person.id}">#{person.name}</option>
345
- #
346
- # This is more often than not used inside a #select_tag like this example:
347
- # select_tag 'person', options_from_collection_for_select(@people, 'id', 'name')
348
- #
349
- # If +selected+ is specified as a value or array of values, the element(s) returning a match on +value_method+
350
- # will be selected option tag(s).
351
- #
352
- # If +selected+ is specified as a Proc, those members of the collection that return true for the anonymous
353
- # function are the selected values.
354
- #
355
- # +selected+ can also be a hash, specifying both <tt>:selected</tt> and/or <tt>:disabled</tt> values as required.
356
- #
357
- # Be sure to specify the same class as the +value_method+ when specifying selected or disabled options.
358
- # Failure to do this will produce undesired results. Example:
359
- # options_from_collection_for_select(@people, 'id', 'name', '1')
360
- # Will not select a person with the id of 1 because 1 (an Integer) is not the same as '1' (a string)
361
- # options_from_collection_for_select(@people, 'id', 'name', 1)
362
- # should produce the desired results.
363
- def options_from_collection_for_select(collection, value_method, text_method, selected = nil)
364
- options = collection.map do |element|
365
- [element.send(text_method), element.send(value_method)]
366
- end
367
- selected, disabled = extract_selected_and_disabled(selected)
368
- select_deselect = {}
369
- select_deselect[:selected] = extract_values_from_collection(collection, value_method, selected)
370
- select_deselect[:disabled] = extract_values_from_collection(collection, value_method, disabled)
371
-
372
- options_for_select(options, select_deselect)
373
- end
374
-
375
- # Returns a string of <tt><option></tt> tags, like <tt>options_from_collection_for_select</tt>, but
376
- # groups them by <tt><optgroup></tt> tags based on the object relationships of the arguments.
377
- #
378
- # Parameters:
379
- # * +collection+ - An array of objects representing the <tt><optgroup></tt> tags.
380
- # * +group_method+ - The name of a method which, when called on a member of +collection+, returns an
381
- # array of child objects representing the <tt><option></tt> tags.
382
- # * group_label_method+ - The name of a method which, when called on a member of +collection+, returns a
383
- # string to be used as the +label+ attribute for its <tt><optgroup></tt> tag.
384
- # * +option_key_method+ - The name of a method which, when called on a child object of a member of
385
- # +collection+, returns a value to be used as the +value+ attribute for its <tt><option></tt> tag.
386
- # * +option_value_method+ - The name of a method which, when called on a child object of a member of
387
- # +collection+, returns a value to be used as the contents of its <tt><option></tt> tag.
388
- # * +selected_key+ - A value equal to the +value+ attribute for one of the <tt><option></tt> tags,
389
- # which will have the +selected+ attribute set. Corresponds to the return value of one of the calls
390
- # to +option_key_method+. If +nil+, no selection is made. Can also be a hash if disabled values are
391
- # to be specified.
392
- #
393
- # Example object structure for use with this method:
394
- # class Continent < ActiveRecord::Base
395
- # has_many :countries
396
- # # attribs: id, name
397
- # end
398
- # class Country < ActiveRecord::Base
399
- # belongs_to :continent
400
- # # attribs: id, name, continent_id
401
- # end
402
- #
403
- # Sample usage:
404
- # option_groups_from_collection_for_select(@continents, :countries, :name, :id, :name, 3)
405
- #
406
- # Possible output:
407
- # <optgroup label="Africa">
408
- # <option value="1">Egypt</option>
409
- # <option value="4">Rwanda</option>
410
- # ...
411
- # </optgroup>
412
- # <optgroup label="Asia">
413
- # <option value="3" selected="selected">China</option>
414
- # <option value="12">India</option>
415
- # <option value="5">Japan</option>
416
- # ...
417
- # </optgroup>
418
- #
419
- # <b>Note:</b> Only the <tt><optgroup></tt> and <tt><option></tt> tags are returned, so you still have to
420
- # wrap the output in an appropriate <tt><select></tt> tag.
421
- def option_groups_from_collection_for_select(collection, group_method, group_label_method, option_key_method, option_value_method, selected_key = nil)
422
- collection.map do |group|
423
- group_label_string = eval("group.#{group_label_method}")
424
- "<optgroup label=\"#{ERB::Util.html_escape(group_label_string)}\">" +
425
- options_from_collection_for_select(eval("group.#{group_method}"), option_key_method, option_value_method, selected_key) +
426
- '</optgroup>'
427
- end.join.html_safe
428
- end
429
-
430
- # Returns a string of <tt><option></tt> tags, like <tt>options_for_select</tt>, but
431
- # wraps them with <tt><optgroup></tt> tags.
432
- #
433
- # Parameters:
434
- # * +grouped_options+ - Accepts a nested array or hash of strings. The first value serves as the
435
- # <tt><optgroup></tt> label while the second value must be an array of options. The second value can be a
436
- # nested array of text-value pairs. See <tt>options_for_select</tt> for more info.
437
- # Ex. ["North America",[["United States","US"],["Canada","CA"]]]
438
- # * +selected_key+ - A value equal to the +value+ attribute for one of the <tt><option></tt> tags,
439
- # which will have the +selected+ attribute set. Note: It is possible for this value to match multiple options
440
- # as you might have the same option in multiple groups. Each will then get <tt>selected="selected"</tt>.
441
- # * +prompt+ - set to true or a prompt string. When the select element doesn't have a value yet, this
442
- # prepends an option with a generic prompt - "Please select" - or the given prompt string.
443
- #
444
- # Sample usage (Array):
445
- # grouped_options = [
446
- # ['North America',
447
- # [['United States','US'],'Canada']],
448
- # ['Europe',
449
- # ['Denmark','Germany','France']]
450
- # ]
451
- # grouped_options_for_select(grouped_options)
452
- #
453
- # Sample usage (Hash):
454
- # grouped_options = {
455
- # 'North America' => [['United States','US'], 'Canada'],
456
- # 'Europe' => ['Denmark','Germany','France']
457
- # }
458
- # grouped_options_for_select(grouped_options)
459
- #
460
- # Possible output:
461
- # <optgroup label="Europe">
462
- # <option value="Denmark">Denmark</option>
463
- # <option value="Germany">Germany</option>
464
- # <option value="France">France</option>
465
- # </optgroup>
466
- # <optgroup label="North America">
467
- # <option value="US">United States</option>
468
- # <option value="Canada">Canada</option>
469
- # </optgroup>
470
- #
471
- # <b>Note:</b> Only the <tt><optgroup></tt> and <tt><option></tt> tags are returned, so you still have to
472
- # wrap the output in an appropriate <tt><select></tt> tag.
473
- def grouped_options_for_select(grouped_options, selected_key = nil, prompt = nil)
474
- body = ''
475
- body << content_tag(:option, prompt, { :value => "" }, true) if prompt
476
-
477
- grouped_options = grouped_options.sort if grouped_options.is_a?(Hash)
478
-
479
- grouped_options.each do |group|
480
- body << content_tag(:optgroup, options_for_select(group[1], selected_key), :label => group[0])
481
- end
482
-
483
- body.html_safe
484
- end
485
-
486
- # Returns a string of option tags for pretty much any time zone in the
487
- # world. Supply a ActiveSupport::TimeZone name as +selected+ to have it
488
- # marked as the selected option tag. You can also supply an array of
489
- # ActiveSupport::TimeZone objects as +priority_zones+, so that they will
490
- # be listed above the rest of the (long) list. (You can use
491
- # ActiveSupport::TimeZone.us_zones as a convenience for obtaining a list
492
- # of the US time zones, or a Regexp to select the zones of your choice)
493
- #
494
- # The +selected+ parameter must be either +nil+, or a string that names
495
- # a ActiveSupport::TimeZone.
496
- #
497
- # By default, +model+ is the ActiveSupport::TimeZone constant (which can
498
- # be obtained in Active Record as a value object). The only requirement
499
- # is that the +model+ parameter be an object that responds to +all+, and
500
- # returns an array of objects that represent time zones.
501
- #
502
- # NOTE: Only the option tags are returned, you have to wrap this call in
503
- # a regular HTML select tag.
504
- def time_zone_options_for_select(selected = nil, priority_zones = nil, model = ::ActiveSupport::TimeZone)
505
- zone_options = ""
506
-
507
- zones = model.all
508
- convert_zones = lambda { |list| list.map { |z| [ z.to_s, z.name ] } }
509
-
510
- if priority_zones
511
- if priority_zones.is_a?(Regexp)
512
- priority_zones = model.all.find_all {|z| z =~ priority_zones}
513
- end
514
- zone_options += options_for_select(convert_zones[priority_zones], selected)
515
- zone_options += "<option value=\"\" disabled=\"disabled\">-------------</option>\n"
516
-
517
- zones = zones.reject { |z| priority_zones.include?( z ) }
518
- end
519
-
520
- zone_options += options_for_select(convert_zones[zones], selected)
521
- zone_options.html_safe
522
- end
523
-
524
- private
525
- def option_html_attributes(element)
526
- return "" unless Array === element
527
- html_attributes = []
528
- element.select { |e| Hash === e }.reduce({}, :merge).each do |k, v|
529
- html_attributes << " #{k}=\"#{ERB::Util.html_escape(v.to_s)}\""
530
- end
531
- html_attributes.join
532
- end
533
-
534
- def option_text_and_value(option)
535
- # Options are [text, value] pairs or strings used for both.
536
- case
537
- when Array === option
538
- option = option.reject { |e| Hash === e }
539
- [option.first, option.last]
540
- when !option.is_a?(String) && option.respond_to?(:first) && option.respond_to?(:last)
541
- [option.first, option.last]
542
- else
543
- [option, option]
544
- end
545
- end
546
-
547
- def option_value_selected?(value, selected)
548
- if selected.respond_to?(:include?) && !selected.is_a?(String)
549
- selected.include? value
550
- else
551
- value == selected
552
- end
553
- end
554
-
555
- def extract_selected_and_disabled(selected)
556
- if selected.is_a?(Proc)
557
- [ selected, nil ]
558
- else
559
- selected = Array.wrap(selected)
560
- options = selected.extract_options!.symbolize_keys
561
- [ options.include?(:selected) ? options[:selected] : selected, options[:disabled] ]
562
- end
563
- end
564
-
565
- def extract_values_from_collection(collection, value_method, selected)
566
- if selected.is_a?(Proc)
567
- collection.map do |element|
568
- element.send(value_method) if selected.call(element)
569
- end.compact
570
- else
571
- selected
572
- end
573
- end
574
- end
575
-
576
- class InstanceTag #:nodoc:
577
- include FormOptionsHelper
578
-
579
- def to_select_tag(choices, options, html_options)
580
- selected_value = options.has_key?(:selected) ? options[:selected] : value(object)
581
- choices = choices.to_a if choices.is_a?(Range)
582
-
583
- # Grouped choices look like this:
584
- #
585
- # [nil, []]
586
- # { nil => [] }
587
- #
588
- if !choices.empty? && choices.first.respond_to?(:last) && Array === choices.first.last
589
- option_tags = grouped_options_for_select(choices, :selected => selected_value, :disabled => options[:disabled])
590
- else
591
- option_tags = options_for_select(choices, :selected => selected_value, :disabled => options[:disabled])
592
- end
593
-
594
- select_content_tag(option_tags, options, html_options)
595
- end
596
-
597
- def to_collection_select_tag(collection, value_method, text_method, options, html_options)
598
- selected_value = options.has_key?(:selected) ? options[:selected] : value(object)
599
- select_content_tag(
600
- options_from_collection_for_select(collection, value_method, text_method, :selected => selected_value, :disabled => options[:disabled]), options, html_options
601
- )
602
- end
603
-
604
- def to_grouped_collection_select_tag(collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options)
605
- select_content_tag(
606
- option_groups_from_collection_for_select(collection, group_method, group_label_method, option_key_method, option_value_method, value(object)), options, html_options
607
- )
608
- end
609
-
610
- def to_time_zone_select_tag(priority_zones, options, html_options)
611
- select_content_tag(
612
- time_zone_options_for_select(value(object) || options[:default], priority_zones, options[:model] || ActiveSupport::TimeZone), options, html_options
613
- )
614
- end
615
-
616
- private
617
- def add_options(option_tags, options, value = nil)
618
- if options[:include_blank]
619
- option_tags = content_tag_string('option', options[:include_blank].kind_of?(String) ? options[:include_blank] : nil, :value => '') + "\n" + option_tags
620
- end
621
- if value.blank? && options[:prompt]
622
- prompt = options[:prompt].kind_of?(String) ? options[:prompt] : I18n.translate('helpers.select.prompt', :default => 'Please select')
623
- option_tags = content_tag_string('option', prompt, :value => '') + "\n" + option_tags
624
- end
625
- option_tags
626
- end
627
-
628
- def select_content_tag(option_tags, options, html_options)
629
- html_options = html_options.stringify_keys
630
- add_default_name_and_id(html_options)
631
- select = content_tag("select", add_options(option_tags, options, value(object)), html_options)
632
- if html_options["multiple"]
633
- tag("input", :disabled => html_options["disabled"], :name => html_options["name"], :type => "hidden", :value => "") + select
634
- else
635
- select
636
- end
637
- end
638
- end
639
-
640
- class FormBuilder
641
- def select(method, choices, options = {}, html_options = {})
642
- @template.select(@object_name, method, choices, objectify_options(options), @default_options.merge(html_options))
643
- end
644
-
645
- def collection_select(method, collection, value_method, text_method, options = {}, html_options = {})
646
- @template.collection_select(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_options.merge(html_options))
647
- end
648
-
649
- def grouped_collection_select(method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {})
650
- @template.grouped_collection_select(@object_name, method, collection, group_method, group_label_method, option_key_method, option_value_method, objectify_options(options), @default_options.merge(html_options))
651
- end
652
-
653
- def time_zone_select(method, priority_zones = nil, options = {}, html_options = {})
654
- @template.time_zone_select(@object_name, method, priority_zones, objectify_options(options), @default_options.merge(html_options))
655
- end
656
- end
657
- end
658
- end