actionpack 2.0.5 → 2.1.0

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 (210) hide show
  1. data/CHANGELOG +149 -7
  2. data/MIT-LICENSE +1 -1
  3. data/README +1 -1
  4. data/Rakefile +5 -6
  5. data/lib/action_controller.rb +2 -2
  6. data/lib/action_controller/assertions/model_assertions.rb +2 -1
  7. data/lib/action_controller/assertions/response_assertions.rb +4 -2
  8. data/lib/action_controller/assertions/routing_assertions.rb +3 -3
  9. data/lib/action_controller/assertions/selector_assertions.rb +30 -27
  10. data/lib/action_controller/assertions/tag_assertions.rb +3 -3
  11. data/lib/action_controller/base.rb +103 -129
  12. data/lib/action_controller/benchmarking.rb +3 -3
  13. data/lib/action_controller/caching.rb +41 -652
  14. data/lib/action_controller/caching/actions.rb +144 -0
  15. data/lib/action_controller/caching/fragments.rb +138 -0
  16. data/lib/action_controller/caching/pages.rb +154 -0
  17. data/lib/action_controller/caching/sql_cache.rb +18 -0
  18. data/lib/action_controller/caching/sweeping.rb +97 -0
  19. data/lib/action_controller/cgi_ext/cookie.rb +27 -23
  20. data/lib/action_controller/cgi_ext/stdinput.rb +1 -0
  21. data/lib/action_controller/cgi_process.rb +6 -4
  22. data/lib/action_controller/components.rb +7 -6
  23. data/lib/action_controller/cookies.rb +31 -19
  24. data/lib/action_controller/dispatcher.rb +51 -84
  25. data/lib/action_controller/filters.rb +295 -421
  26. data/lib/action_controller/flash.rb +1 -6
  27. data/lib/action_controller/headers.rb +31 -0
  28. data/lib/action_controller/helpers.rb +26 -9
  29. data/lib/action_controller/http_authentication.rb +1 -1
  30. data/lib/action_controller/integration.rb +65 -13
  31. data/lib/action_controller/layout.rb +24 -39
  32. data/lib/action_controller/mime_responds.rb +7 -3
  33. data/lib/action_controller/mime_type.rb +25 -9
  34. data/lib/action_controller/mime_types.rb +1 -1
  35. data/lib/action_controller/polymorphic_routes.rb +32 -17
  36. data/lib/action_controller/record_identifier.rb +10 -4
  37. data/lib/action_controller/request.rb +46 -30
  38. data/lib/action_controller/request_forgery_protection.rb +10 -9
  39. data/lib/action_controller/request_profiler.rb +29 -8
  40. data/lib/action_controller/rescue.rb +24 -24
  41. data/lib/action_controller/resources.rb +66 -23
  42. data/lib/action_controller/response.rb +2 -2
  43. data/lib/action_controller/routing.rb +113 -1229
  44. data/lib/action_controller/routing/builder.rb +204 -0
  45. data/lib/action_controller/{routing_optimisation.rb → routing/optimisations.rb} +13 -12
  46. data/lib/action_controller/routing/recognition_optimisation.rb +158 -0
  47. data/lib/action_controller/routing/route.rb +240 -0
  48. data/lib/action_controller/routing/route_set.rb +435 -0
  49. data/lib/action_controller/routing/routing_ext.rb +46 -0
  50. data/lib/action_controller/routing/segments.rb +283 -0
  51. data/lib/action_controller/session/active_record_store.rb +13 -8
  52. data/lib/action_controller/session/cookie_store.rb +20 -17
  53. data/lib/action_controller/session_management.rb +10 -3
  54. data/lib/action_controller/streaming.rb +45 -31
  55. data/lib/action_controller/test_case.rb +33 -23
  56. data/lib/action_controller/test_process.rb +39 -35
  57. data/lib/action_controller/url_rewriter.rb +18 -12
  58. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +1 -1
  59. data/lib/action_pack.rb +1 -1
  60. data/lib/action_pack/version.rb +2 -2
  61. data/lib/action_view.rb +11 -3
  62. data/lib/action_view/base.rb +73 -390
  63. data/lib/action_view/helpers/active_record_helper.rb +83 -62
  64. data/lib/action_view/helpers/asset_tag_helper.rb +101 -44
  65. data/lib/action_view/helpers/atom_feed_helper.rb +35 -7
  66. data/lib/action_view/helpers/benchmark_helper.rb +5 -3
  67. data/lib/action_view/helpers/cache_helper.rb +3 -2
  68. data/lib/action_view/helpers/capture_helper.rb +1 -2
  69. data/lib/action_view/helpers/date_helper.rb +104 -82
  70. data/lib/action_view/helpers/form_helper.rb +148 -75
  71. data/lib/action_view/helpers/form_options_helper.rb +44 -23
  72. data/lib/action_view/helpers/form_tag_helper.rb +22 -13
  73. data/lib/action_view/helpers/javascripts/controls.js +1 -1
  74. data/lib/action_view/helpers/javascripts/dragdrop.js +1 -1
  75. data/lib/action_view/helpers/javascripts/effects.js +1 -1
  76. data/lib/action_view/helpers/number_helper.rb +10 -3
  77. data/lib/action_view/helpers/prototype_helper.rb +61 -29
  78. data/lib/action_view/helpers/record_tag_helper.rb +3 -3
  79. data/lib/action_view/helpers/sanitize_helper.rb +23 -17
  80. data/lib/action_view/helpers/scriptaculous_helper.rb +86 -60
  81. data/lib/action_view/helpers/text_helper.rb +153 -125
  82. data/lib/action_view/helpers/url_helper.rb +83 -28
  83. data/lib/action_view/inline_template.rb +20 -0
  84. data/lib/action_view/partial_template.rb +70 -0
  85. data/lib/action_view/partials.rb +31 -73
  86. data/lib/action_view/template.rb +127 -0
  87. data/lib/action_view/template_error.rb +8 -7
  88. data/lib/action_view/template_finder.rb +177 -0
  89. data/lib/action_view/template_handler.rb +18 -1
  90. data/lib/action_view/template_handlers/builder.rb +10 -2
  91. data/lib/action_view/template_handlers/compilable.rb +128 -0
  92. data/lib/action_view/template_handlers/erb.rb +37 -2
  93. data/lib/action_view/template_handlers/rjs.rb +14 -1
  94. data/lib/action_view/test_case.rb +58 -0
  95. data/test/abstract_unit.rb +1 -1
  96. data/test/active_record_unit.rb +3 -6
  97. data/test/activerecord/active_record_store_test.rb +1 -2
  98. data/test/activerecord/render_partial_with_record_identification_test.rb +158 -41
  99. data/test/adv_attr_test.rb +20 -0
  100. data/test/controller/action_pack_assertions_test.rb +16 -19
  101. data/test/controller/addresses_render_test.rb +1 -1
  102. data/test/controller/assert_select_test.rb +13 -6
  103. data/test/controller/base_test.rb +48 -2
  104. data/test/controller/benchmark_test.rb +1 -2
  105. data/test/controller/caching_test.rb +282 -21
  106. data/test/controller/capture_test.rb +1 -1
  107. data/test/controller/cgi_test.rb +1 -1
  108. data/test/controller/components_test.rb +1 -1
  109. data/test/controller/content_type_test.rb +2 -2
  110. data/test/controller/cookie_test.rb +13 -2
  111. data/test/controller/custom_handler_test.rb +14 -10
  112. data/test/controller/deprecation/deprecated_base_methods_test.rb +1 -1
  113. data/test/controller/dispatcher_test.rb +31 -49
  114. data/test/controller/fake_controllers.rb +17 -0
  115. data/test/controller/fake_models.rb +6 -0
  116. data/test/controller/filter_params_test.rb +14 -8
  117. data/test/controller/filters_test.rb +44 -16
  118. data/test/controller/flash_test.rb +2 -2
  119. data/test/controller/header_test.rb +14 -0
  120. data/test/controller/helper_test.rb +19 -15
  121. data/test/controller/html-scanner/document_test.rb +1 -2
  122. data/test/controller/html-scanner/node_test.rb +1 -2
  123. data/test/controller/html-scanner/sanitizer_test.rb +8 -5
  124. data/test/controller/html-scanner/tag_node_test.rb +1 -2
  125. data/test/controller/html-scanner/text_node_test.rb +2 -3
  126. data/test/controller/html-scanner/tokenizer_test.rb +8 -2
  127. data/test/controller/http_authentication_test.rb +1 -1
  128. data/test/controller/integration_test.rb +14 -16
  129. data/test/controller/integration_upload_test.rb +43 -0
  130. data/test/controller/layout_test.rb +26 -6
  131. data/test/controller/mime_responds_test.rb +39 -7
  132. data/test/controller/mime_type_test.rb +29 -5
  133. data/test/controller/new_render_test.rb +105 -34
  134. data/test/controller/polymorphic_routes_test.rb +32 -20
  135. data/test/controller/record_identifier_test.rb +38 -2
  136. data/test/controller/redirect_test.rb +21 -1
  137. data/test/controller/render_test.rb +59 -15
  138. data/test/controller/request_forgery_protection_test.rb +92 -5
  139. data/test/controller/request_test.rb +64 -6
  140. data/test/controller/rescue_test.rb +22 -6
  141. data/test/controller/resources_test.rb +102 -14
  142. data/test/controller/routing_test.rb +231 -19
  143. data/test/controller/selector_test.rb +2 -2
  144. data/test/controller/send_file_test.rb +14 -3
  145. data/test/controller/session/cookie_store_test.rb +16 -4
  146. data/test/controller/session/mem_cache_store_test.rb +3 -4
  147. data/test/controller/session_fixation_test.rb +1 -1
  148. data/test/controller/session_management_test.rb +23 -1
  149. data/test/controller/test_test.rb +39 -18
  150. data/test/controller/url_rewriter_test.rb +35 -1
  151. data/test/controller/verification_test.rb +1 -1
  152. data/test/controller/view_paths_test.rb +15 -12
  153. data/test/controller/webservice_test.rb +48 -3
  154. data/test/fixtures/bad_customers/_bad_customer.html.erb +1 -0
  155. data/test/fixtures/company.rb +1 -0
  156. data/test/fixtures/customers/_customer.html.erb +1 -0
  157. data/test/fixtures/db_definitions/sqlite.sql +6 -0
  158. data/test/fixtures/functional_caching/_partial.erb +3 -0
  159. data/test/fixtures/functional_caching/fragment_cached.html.erb +2 -0
  160. data/test/fixtures/functional_caching/html_fragment_cached_with_partial.html.erb +1 -0
  161. data/test/fixtures/functional_caching/js_fragment_cached_with_partial.js.rjs +1 -0
  162. data/test/fixtures/good_customers/_good_customer.html.erb +1 -0
  163. data/test/fixtures/mascot.rb +3 -0
  164. data/test/fixtures/mascots.yml +4 -0
  165. data/test/fixtures/mascots/_mascot.html.erb +1 -0
  166. data/test/fixtures/multipart/boundary_problem_file +10 -0
  167. data/test/fixtures/public/javascripts/application.js +1 -0
  168. data/test/fixtures/public/javascripts/controls.js +1 -0
  169. data/test/fixtures/public/javascripts/dragdrop.js +1 -0
  170. data/test/fixtures/public/javascripts/effects.js +1 -0
  171. data/test/fixtures/public/javascripts/prototype.js +1 -0
  172. data/test/fixtures/public/javascripts/version.1.0.js +1 -0
  173. data/test/fixtures/public/stylesheets/version.1.0.css +1 -0
  174. data/test/fixtures/reply.rb +1 -0
  175. data/test/fixtures/shared.html.erb +1 -0
  176. data/test/fixtures/symlink_parent/symlinked_layout.erb +5 -0
  177. data/test/fixtures/test/_customer_counter.erb +1 -0
  178. data/test/fixtures/test/_form.erb +1 -0
  179. data/test/fixtures/test/_labelling_form.erb +1 -0
  180. data/test/fixtures/test/_raise.html.erb +1 -0
  181. data/test/fixtures/test/greeting.js.rjs +1 -0
  182. data/test/fixtures/topics/_topic.html.erb +1 -0
  183. data/test/template/active_record_helper_test.rb +25 -8
  184. data/test/template/asset_tag_helper_test.rb +100 -17
  185. data/test/template/atom_feed_helper_test.rb +29 -1
  186. data/test/template/benchmark_helper_test.rb +10 -22
  187. data/test/template/date_helper_test.rb +455 -153
  188. data/test/template/erb_util_test.rb +10 -42
  189. data/test/template/form_helper_test.rb +192 -66
  190. data/test/template/form_options_helper_test.rb +19 -8
  191. data/test/template/form_tag_helper_test.rb +11 -8
  192. data/test/template/javascript_helper_test.rb +3 -9
  193. data/test/template/number_helper_test.rb +6 -3
  194. data/test/template/prototype_helper_test.rb +27 -40
  195. data/test/template/record_tag_helper_test.rb +54 -0
  196. data/test/template/sanitize_helper_test.rb +5 -6
  197. data/test/template/scriptaculous_helper_test.rb +7 -13
  198. data/test/template/tag_helper_test.rb +3 -6
  199. data/test/template/template_finder_test.rb +73 -0
  200. data/test/template/template_object_test.rb +95 -0
  201. data/test/template/test_test.rb +56 -0
  202. data/test/template/text_helper_test.rb +46 -33
  203. data/test/template/url_helper_test.rb +8 -10
  204. metadata +65 -12
  205. data/lib/action_view/compiled_templates.rb +0 -69
  206. data/test/action_view_test.rb +0 -44
  207. data/test/activerecord/fixtures_test.rb +0 -24
  208. data/test/controller/fragment_store_setting_test.rb +0 -47
  209. data/test/template/compiled_templates_test.rb +0 -197
  210. data/test/template/deprecate_ivars_test.rb +0 -51
@@ -26,7 +26,7 @@ module ActionView
26
26
  # end
27
27
  #
28
28
  # app/views/posts/index.atom.builder:
29
- # atom_feed(:tag_uri => "2008") do |feed|
29
+ # atom_feed do |feed|
30
30
  # feed.title("My great blog!")
31
31
  # feed.updated((@posts.first.created_at))
32
32
  #
@@ -42,25 +42,53 @@ module ActionView
42
42
  # end
43
43
  # end
44
44
  #
45
- # The options are for atom_feed are:
45
+ # The options for atom_feed are:
46
46
  #
47
- # * <tt>:schema_date</tt>: Required. The date at which the tag scheme for the feed was first used. A good default is the year you created the feed. See http://feedvalidator.org/docs/error/InvalidTAG.html for more information.
48
47
  # * <tt>:language</tt>: Defaults to "en-US".
49
48
  # * <tt>:root_url</tt>: The HTML alternative that this feed is doubling for. Defaults to / on the current host.
50
49
  # * <tt>:url</tt>: The URL for this feed. Defaults to the current URL.
50
+ # * <tt>:schema_date</tt>: The date at which the tag scheme for the feed was first used. A good default is the year you
51
+ # created the feed. See http://feedvalidator.org/docs/error/InvalidTAG.html for more information. If not specified,
52
+ # 2005 is used (as an "I don't care" value).
53
+ #
54
+ # Other namespaces can be added to the root element:
55
+ #
56
+ # app/views/posts/index.atom.builder:
57
+ # atom_feed({'xmlns:app' => 'http://www.w3.org/2007/app',
58
+ # 'xmlns:openSearch' => 'http://a9.com/-/spec/opensearch/1.1/'}) do |feed|
59
+ # feed.title("My great blog!")
60
+ # feed.updated((@posts.first.created_at))
61
+ # feed.tag!(openSearch:totalResults, 10)
62
+ #
63
+ # for post in @posts
64
+ # feed.entry(post) do |entry|
65
+ # entry.title(post.title)
66
+ # entry.content(post.body, :type => 'html')
67
+ # entry.tag!('app:edited', Time.now)
68
+ #
69
+ # entry.author do |author|
70
+ # author.name("DHH")
71
+ # end
72
+ # end
73
+ # end
74
+ # end
75
+ #
51
76
  #
52
77
  # atom_feed yields an AtomFeedBuilder instance.
53
78
  def atom_feed(options = {}, &block)
54
- if options[:schema_date].blank?
55
- logger.warn("You must provide the :schema_date option to atom_feed for your feed to be valid. A good default is the year you first created this feed.") unless logger.nil?
56
- else
79
+ if options[:schema_date]
57
80
  options[:schema_date] = options[:schema_date].strftime("%Y-%m-%d") if options[:schema_date].respond_to?(:strftime)
81
+ else
82
+ options[:schema_date] = "2005" # The Atom spec copyright date
58
83
  end
59
84
 
60
85
  xml = options[:xml] || eval("xml", block.binding)
61
86
  xml.instruct!
62
87
 
63
- xml.feed "xml:lang" => options[:language] || "en-US", "xmlns" => 'http://www.w3.org/2005/Atom' do
88
+ feed_opts = {"xml:lang" => options[:language] || "en-US", "xmlns" => 'http://www.w3.org/2005/Atom'}
89
+ feed_opts.merge!(options).reject!{|k,v| !k.to_s.match(/^xml/)}
90
+
91
+ xml.feed(feed_opts) do
64
92
  xml.id("tag:#{request.host},#{options[:schema_date]}:#{request.request_uri.split(".")[0]}")
65
93
  xml.link(:rel => 'alternate', :type => 'text/html', :href => options[:root_url] || (request.protocol + request.host_with_port))
66
94
  xml.link(:rel => 'self', :type => 'application/atom+xml', :href => options[:url] || request.url)
@@ -21,11 +21,13 @@ module ActionView
21
21
  # You may give an optional logger level as the second argument
22
22
  # (:debug, :info, :warn, :error); the default value is :info.
23
23
  def benchmark(message = "Benchmarking", level = :info)
24
- if @logger
24
+ if controller.logger
25
25
  real = Benchmark.realtime { yield }
26
- @logger.send level, "#{message} (#{'%.5f' % real})"
26
+ controller.logger.send(level, "#{message} (#{'%.5f' % real})")
27
+ else
28
+ yield
27
29
  end
28
30
  end
29
31
  end
30
32
  end
31
- end
33
+ end
@@ -31,8 +31,9 @@ module ActionView
31
31
  # <%= render :partial => "topics", :collection => @topic_list %>
32
32
  # <i>Topics listed alphabetically</i>
33
33
  # <% end %>
34
- def cache(name = {}, &block)
35
- @controller.cache_erb_fragment(block, name)
34
+ def cache(name = {}, options = nil, &block)
35
+ handler = Template.handler_class_for_extension(current_render_extension.to_sym)
36
+ handler.new(@controller).cache_fragment(block, name, options)
36
37
  end
37
38
  end
38
39
  end
@@ -118,8 +118,7 @@ module ActionView
118
118
  # for elements that will be fragment cached.
119
119
  #
120
120
  # The deprecated way of accessing a content_for block is to use an instance variable
121
- # named <tt>@content_for_#{name_of_the_content_block}</tt>. So <tt><%= content_for :footer %></tt>
122
- # would be available as <tt><%= @content_for_footer %></tt>. The preferred usage is now
121
+ # named <tt>@content_for_#{name_of_the_content_block}</tt>. The preferred usage is now
123
122
  # <tt><%= yield :footer %></tt>.
124
123
  def content_for(name, content = nil, &block)
125
124
  existing_content_for = instance_variable_get("@content_for_#{name}").to_s
@@ -1,4 +1,5 @@
1
1
  require "date"
2
+ require 'action_view/helpers/tag_helper'
2
3
 
3
4
  module ActionView
4
5
  module Helpers
@@ -11,31 +12,32 @@ module ActionView
11
12
  # * <tt>:discard_type</tt> - set to true if you want to discard the type part of the select name. If set to true, the select_month
12
13
  # method would use simply "date" (which can be overwritten using <tt>:prefix</tt>) instead of "date[month]".
13
14
  module DateHelper
15
+ include ActionView::Helpers::TagHelper
14
16
  DEFAULT_PREFIX = 'date' unless const_defined?('DEFAULT_PREFIX')
15
17
 
16
18
  # Reports the approximate distance in time between two Time or Date objects or integers as seconds.
17
19
  # Set <tt>include_seconds</tt> to true if you want more detailed approximations when distance < 1 min, 29 secs
18
- # Distances are reported base on the following table:
19
- #
20
- # 0 <-> 29 secs # => less than a minute
21
- # 30 secs <-> 1 min, 29 secs # => 1 minute
22
- # 1 min, 30 secs <-> 44 mins, 29 secs # => [2..44] minutes
23
- # 44 mins, 30 secs <-> 89 mins, 29 secs # => about 1 hour
24
- # 89 mins, 29 secs <-> 23 hrs, 59 mins, 29 secs # => about [2..24] hours
25
- # 23 hrs, 59 mins, 29 secs <-> 47 hrs, 59 mins, 29 secs # => 1 day
26
- # 47 hrs, 59 mins, 29 secs <-> 29 days, 23 hrs, 59 mins, 29 secs # => [2..29] days
27
- # 29 days, 23 hrs, 59 mins, 30 secs <-> 59 days, 23 hrs, 59 mins, 29 secs # => about 1 month
28
- # 59 days, 23 hrs, 59 mins, 30 secs <-> 1 yr minus 1 sec # => [2..12] months
29
- # 1 yr <-> 2 yrs minus 1 secs # => about 1 year
30
- # 2 yrs <-> max time or date # => over [2..X] years
31
- #
32
- # With include_seconds = true and the difference < 1 minute 29 seconds
33
- # 0-4 secs # => less than 5 seconds
34
- # 5-9 secs # => less than 10 seconds
35
- # 10-19 secs # => less than 20 seconds
36
- # 20-39 secs # => half a minute
37
- # 40-59 secs # => less than a minute
38
- # 60-89 secs # => 1 minute
20
+ # Distances are reported based on the following table:
21
+ #
22
+ # 0 <-> 29 secs # => less than a minute
23
+ # 30 secs <-> 1 min, 29 secs # => 1 minute
24
+ # 1 min, 30 secs <-> 44 mins, 29 secs # => [2..44] minutes
25
+ # 44 mins, 30 secs <-> 89 mins, 29 secs # => about 1 hour
26
+ # 89 mins, 29 secs <-> 23 hrs, 59 mins, 29 secs # => about [2..24] hours
27
+ # 23 hrs, 59 mins, 29 secs <-> 47 hrs, 59 mins, 29 secs # => 1 day
28
+ # 47 hrs, 59 mins, 29 secs <-> 29 days, 23 hrs, 59 mins, 29 secs # => [2..29] days
29
+ # 29 days, 23 hrs, 59 mins, 30 secs <-> 59 days, 23 hrs, 59 mins, 29 secs # => about 1 month
30
+ # 59 days, 23 hrs, 59 mins, 30 secs <-> 1 yr minus 1 sec # => [2..12] months
31
+ # 1 yr <-> 2 yrs minus 1 secs # => about 1 year
32
+ # 2 yrs <-> max time or date # => over [2..X] years
33
+ #
34
+ # With <tt>include_seconds</tt> = true and the difference < 1 minute 29 seconds:
35
+ # 0-4 secs # => less than 5 seconds
36
+ # 5-9 secs # => less than 10 seconds
37
+ # 10-19 secs # => less than 20 seconds
38
+ # 20-39 secs # => half a minute
39
+ # 40-59 secs # => less than a minute
40
+ # 60-89 secs # => 1 minute
39
41
  #
40
42
  # ==== Examples
41
43
  # from_time = Time.now
@@ -102,15 +104,17 @@ module ActionView
102
104
 
103
105
  # Returns a set of select tags (one for year, month, and day) pre-selected for accessing a specified date-based attribute (identified by
104
106
  # +method+) on an object assigned to the template (identified by +object+). It's possible to tailor the selects through the +options+ hash,
105
- # which accepts all the keys that each of the individual select builders do (like :use_month_numbers for select_month) as well as a range of
107
+ # which accepts all the keys that each of the individual select builders do (like <tt>:use_month_numbers</tt> for select_month) as well as a range of
106
108
  # discard options. The discard options are <tt>:discard_year</tt>, <tt>:discard_month</tt> and <tt>:discard_day</tt>. Set to true, they'll
107
109
  # drop the respective select. Discarding the month select will also automatically discard the day select. It's also possible to explicitly
108
110
  # set the order of the tags using the <tt>:order</tt> option with an array of symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in
109
111
  # the desired order. Symbols may be omitted and the respective select is not included.
110
112
  #
111
- # Pass the <tt>:default</tt> option to set the default date. Use a Time object or a Hash of :year, :month, :day, :hour, :minute, and :second.
113
+ # Pass the <tt>:default</tt> option to set the default date. Use a Time object or a Hash of <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>, <tt>:hour</tt>, <tt>:minute</tt>, and <tt>:second</tt>.
112
114
  #
113
- # Passing :disabled => true as part of the +options+ will make elements inaccessible for change.
115
+ # Passing <tt>:disabled => true</tt> as part of the +options+ will make elements inaccessible for change.
116
+ #
117
+ # If anything is passed in the +html_options+ hash it will be applied to every select tag in the set.
114
118
  #
115
119
  # NOTE: Discarded selects will default to 1. So if no month select is available, January will be assumed.
116
120
  #
@@ -148,14 +152,16 @@ module ActionView
148
152
  #
149
153
  # Note: If the day is not included as an option but the month is, the day will be set to the 1st to ensure that all month
150
154
  # choices are valid.
151
- def date_select(object_name, method, options = {})
152
- InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_date_select_tag(options)
155
+ def date_select(object_name, method, options = {}, html_options = {})
156
+ InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_date_select_tag(options, html_options)
153
157
  end
154
158
 
155
159
  # Returns a set of select tags (one for hour, minute and optionally second) pre-selected for accessing a specified
156
160
  # time-based attribute (identified by +method+) on an object assigned to the template (identified by +object+).
157
161
  # You can include the seconds with <tt>:include_seconds</tt>.
158
162
  #
163
+ # If anything is passed in the html_options hash it will be applied to every select tag in the set.
164
+ #
159
165
  # ==== Examples
160
166
  # # Creates a time select tag that, when POSTed, will be stored in the post variable in the sunrise attribute
161
167
  # time_select("post", "sunrise")
@@ -181,13 +187,15 @@ module ActionView
181
187
  #
182
188
  # Note: If the day is not included as an option but the month is, the day will be set to the 1st to ensure that all month
183
189
  # choices are valid.
184
- def time_select(object_name, method, options = {})
185
- InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_time_select_tag(options)
190
+ def time_select(object_name, method, options = {}, html_options = {})
191
+ InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_time_select_tag(options, html_options)
186
192
  end
187
193
 
188
194
  # Returns a set of select tags (one for year, month, day, hour, and minute) pre-selected for accessing a specified datetime-based
189
195
  # attribute (identified by +method+) on an object assigned to the template (identified by +object+). Examples:
190
196
  #
197
+ # If anything is passed in the html_options hash it will be applied to every select tag in the set.
198
+ #
191
199
  # ==== Examples
192
200
  # # Generates a datetime select that, when POSTed, will be stored in the post variable in the written_on attribute
193
201
  # datetime_select("post", "written_on")
@@ -205,8 +213,8 @@ module ActionView
205
213
  # datetime_select("post", "written_on", :discard_type => true)
206
214
  #
207
215
  # The selects are prepared for multi-parameter assignment to an Active Record object.
208
- def datetime_select(object_name, method, options = {})
209
- InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_datetime_select_tag(options)
216
+ def datetime_select(object_name, method, options = {}, html_options = {})
217
+ InstanceTag.new(object_name, method, self, nil, options.delete(:object)).to_datetime_select_tag(options, html_options)
210
218
  end
211
219
 
212
220
  # Returns a set of html select-tags (one for year, month, day, hour, and minute) pre-selected with the +datetime+.
@@ -215,6 +223,8 @@ module ActionView
215
223
  # will be appended onto the <tt>:order</tt> passed in. You can also add <tt>:date_separator</tt> and <tt>:time_separator</tt>
216
224
  # keys to the +options+ to control visual display of the elements.
217
225
  #
226
+ # If anything is passed in the html_options hash it will be applied to every select tag in the set.
227
+ #
218
228
  # ==== Examples
219
229
  # my_date_time = Time.now + 4.days
220
230
  #
@@ -240,9 +250,9 @@ module ActionView
240
250
  # # prefixed with 'payday' rather than 'date'
241
251
  # select_datetime(my_date_time, :prefix => 'payday')
242
252
  #
243
- def select_datetime(datetime = Time.now, options = {})
253
+ def select_datetime(datetime = Time.current, options = {}, html_options = {})
244
254
  separator = options[:datetime_separator] || ''
245
- select_date(datetime, options) + separator + select_time(datetime, options)
255
+ select_date(datetime, options, html_options) + separator + select_time(datetime, options, html_options)
246
256
  end
247
257
 
248
258
  # Returns a set of html select-tags (one for year, month, and day) pre-selected with the +date+.
@@ -250,6 +260,8 @@ module ActionView
250
260
  # symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in the desired order. If you do not supply a Symbol, it
251
261
  # will be appended onto the <tt>:order</tt> passed in.
252
262
  #
263
+ # If anything is passed in the html_options hash it will be applied to every select tag in the set.
264
+ #
253
265
  # ==== Examples
254
266
  # my_date = Time.today + 6.days
255
267
  #
@@ -271,13 +283,13 @@ module ActionView
271
283
  # # prefixed with 'payday' rather than 'date'
272
284
  # select_datetime(my_date_time, :prefix => 'payday')
273
285
  #
274
- def select_date(date = Date.today, options = {})
286
+ def select_date(date = Date.current, options = {}, html_options = {})
275
287
  options[:order] ||= []
276
288
  [:year, :month, :day].each { |o| options[:order].push(o) unless options[:order].include?(o) }
277
289
 
278
290
  select_date = ''
279
291
  options[:order].each do |o|
280
- select_date << self.send("select_#{o}", date, options)
292
+ select_date << self.send("select_#{o}", date, options, html_options)
281
293
  end
282
294
  select_date
283
295
  end
@@ -286,6 +298,8 @@ module ActionView
286
298
  # You can set <tt>:time_separator</tt> key to format the output, and
287
299
  # the <tt>:include_seconds</tt> option to include an input for seconds.
288
300
  #
301
+ # If anything is passed in the html_options hash it will be applied to every select tag in the set.
302
+ #
289
303
  # ==== Examples
290
304
  # my_time = Time.now + 5.days + 7.hours + 3.minutes + 14.seconds
291
305
  #
@@ -307,9 +321,9 @@ module ActionView
307
321
  # # separated by ':' and includes an input for seconds
308
322
  # select_time(my_time, :time_separator => ':', :include_seconds => true)
309
323
  #
310
- def select_time(datetime = Time.now, options = {})
324
+ def select_time(datetime = Time.current, options = {}, html_options = {})
311
325
  separator = options[:time_separator] || ''
312
- select_hour(datetime, options) + separator + select_minute(datetime, options) + (options[:include_seconds] ? separator + select_second(datetime, options) : '')
326
+ select_hour(datetime, options, html_options) + separator + select_minute(datetime, options, html_options) + (options[:include_seconds] ? separator + select_second(datetime, options, html_options) : '')
313
327
  end
314
328
 
315
329
  # Returns a select tag with options for each of the seconds 0 through 59 with the current second selected.
@@ -329,7 +343,7 @@ module ActionView
329
343
  # # that is named 'interval' rather than 'second'
330
344
  # select_second(my_time, :field_name => 'interval')
331
345
  #
332
- def select_second(datetime, options = {})
346
+ def select_second(datetime, options = {}, html_options = {})
333
347
  val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.sec) : ''
334
348
  if options[:use_hidden]
335
349
  options[:include_seconds] ? hidden_html(options[:field_name] || 'second', val, options) : ''
@@ -337,11 +351,12 @@ module ActionView
337
351
  second_options = []
338
352
  0.upto(59) do |second|
339
353
  second_options << ((val == second) ?
340
- %(<option value="#{leading_zero_on_single_digits(second)}" selected="selected">#{leading_zero_on_single_digits(second)}</option>\n) :
341
- %(<option value="#{leading_zero_on_single_digits(second)}">#{leading_zero_on_single_digits(second)}</option>\n)
354
+ content_tag(:option, leading_zero_on_single_digits(second), :value => leading_zero_on_single_digits(second), :selected => "selected") :
355
+ content_tag(:option, leading_zero_on_single_digits(second), :value => leading_zero_on_single_digits(second))
342
356
  )
357
+ second_options << "\n"
343
358
  end
344
- select_html(options[:field_name] || 'second', second_options.join, options)
359
+ select_html(options[:field_name] || 'second', second_options.join, options, html_options)
345
360
  end
346
361
  end
347
362
 
@@ -363,7 +378,7 @@ module ActionView
363
378
  # # that is named 'stride' rather than 'second'
364
379
  # select_minute(my_time, :field_name => 'stride')
365
380
  #
366
- def select_minute(datetime, options = {})
381
+ def select_minute(datetime, options = {}, html_options = {})
367
382
  val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.min) : ''
368
383
  if options[:use_hidden]
369
384
  hidden_html(options[:field_name] || 'minute', val, options)
@@ -371,11 +386,12 @@ module ActionView
371
386
  minute_options = []
372
387
  0.step(59, options[:minute_step] || 1) do |minute|
373
388
  minute_options << ((val == minute) ?
374
- %(<option value="#{leading_zero_on_single_digits(minute)}" selected="selected">#{leading_zero_on_single_digits(minute)}</option>\n) :
375
- %(<option value="#{leading_zero_on_single_digits(minute)}">#{leading_zero_on_single_digits(minute)}</option>\n)
389
+ content_tag(:option, leading_zero_on_single_digits(minute), :value => leading_zero_on_single_digits(minute), :selected => "selected") :
390
+ content_tag(:option, leading_zero_on_single_digits(minute), :value => leading_zero_on_single_digits(minute))
376
391
  )
392
+ minute_options << "\n"
377
393
  end
378
- select_html(options[:field_name] || 'minute', minute_options.join, options)
394
+ select_html(options[:field_name] || 'minute', minute_options.join, options, html_options)
379
395
  end
380
396
  end
381
397
 
@@ -396,7 +412,7 @@ module ActionView
396
412
  # # that is named 'stride' rather than 'second'
397
413
  # select_minute(my_time, :field_name => 'stride')
398
414
  #
399
- def select_hour(datetime, options = {})
415
+ def select_hour(datetime, options = {}, html_options = {})
400
416
  val = datetime ? (datetime.kind_of?(Fixnum) ? datetime : datetime.hour) : ''
401
417
  if options[:use_hidden]
402
418
  hidden_html(options[:field_name] || 'hour', val, options)
@@ -404,11 +420,12 @@ module ActionView
404
420
  hour_options = []
405
421
  0.upto(23) do |hour|
406
422
  hour_options << ((val == hour) ?
407
- %(<option value="#{leading_zero_on_single_digits(hour)}" selected="selected">#{leading_zero_on_single_digits(hour)}</option>\n) :
408
- %(<option value="#{leading_zero_on_single_digits(hour)}">#{leading_zero_on_single_digits(hour)}</option>\n)
423
+ content_tag(:option, leading_zero_on_single_digits(hour), :value => leading_zero_on_single_digits(hour), :selected => "selected") :
424
+ content_tag(:option, leading_zero_on_single_digits(hour), :value => leading_zero_on_single_digits(hour))
409
425
  )
426
+ hour_options << "\n"
410
427
  end
411
- select_html(options[:field_name] || 'hour', hour_options.join, options)
428
+ select_html(options[:field_name] || 'hour', hour_options.join, options, html_options)
412
429
  end
413
430
  end
414
431
 
@@ -429,7 +446,7 @@ module ActionView
429
446
  # # that is named 'due' rather than 'day'
430
447
  # select_day(my_time, :field_name => 'due')
431
448
  #
432
- def select_day(date, options = {})
449
+ def select_day(date, options = {}, html_options = {})
433
450
  val = date ? (date.kind_of?(Fixnum) ? date : date.day) : ''
434
451
  if options[:use_hidden]
435
452
  hidden_html(options[:field_name] || 'day', val, options)
@@ -437,11 +454,12 @@ module ActionView
437
454
  day_options = []
438
455
  1.upto(31) do |day|
439
456
  day_options << ((val == day) ?
440
- %(<option value="#{day}" selected="selected">#{day}</option>\n) :
441
- %(<option value="#{day}">#{day}</option>\n)
457
+ content_tag(:option, day, :value => day, :selected => "selected") :
458
+ content_tag(:option, day, :value => day)
442
459
  )
460
+ day_options << "\n"
443
461
  end
444
- select_html(options[:field_name] || 'day', day_options.join, options)
462
+ select_html(options[:field_name] || 'day', day_options.join, options, html_options)
445
463
  end
446
464
  end
447
465
 
@@ -479,7 +497,7 @@ module ActionView
479
497
  # # will use keys like "Januar", "Marts."
480
498
  # select_month(Date.today, :use_month_names => %w(Januar Februar Marts ...))
481
499
  #
482
- def select_month(date, options = {})
500
+ def select_month(date, options = {}, html_options = {})
483
501
  val = date ? (date.kind_of?(Fixnum) ? date : date.month) : ''
484
502
  if options[:use_hidden]
485
503
  hidden_html(options[:field_name] || 'month', val, options)
@@ -497,11 +515,12 @@ module ActionView
497
515
  end
498
516
 
499
517
  month_options << ((val == month_number) ?
500
- %(<option value="#{month_number}" selected="selected">#{month_name}</option>\n) :
501
- %(<option value="#{month_number}">#{month_name}</option>\n)
518
+ content_tag(:option, month_name, :value => month_number, :selected => "selected") :
519
+ content_tag(:option, month_name, :value => month_number)
502
520
  )
521
+ month_options << "\n"
503
522
  end
504
- select_html(options[:field_name] || 'month', month_options.join, options)
523
+ select_html(options[:field_name] || 'month', month_options.join, options, html_options)
505
524
  end
506
525
  end
507
526
 
@@ -527,7 +546,7 @@ module ActionView
527
546
  # # has ascending year values
528
547
  # select_year(2006, :start_year => 2000, :end_year => 2010)
529
548
  #
530
- def select_year(date, options = {})
549
+ def select_year(date, options = {}, html_options = {})
531
550
  val = date ? (date.kind_of?(Fixnum) ? date : date.year) : ''
532
551
  if options[:use_hidden]
533
552
  hidden_html(options[:field_name] || 'year', val, options)
@@ -539,29 +558,31 @@ module ActionView
539
558
  step_val = start_year < end_year ? 1 : -1
540
559
  start_year.step(end_year, step_val) do |year|
541
560
  year_options << ((val == year) ?
542
- %(<option value="#{year}" selected="selected">#{year}</option>\n) :
543
- %(<option value="#{year}">#{year}</option>\n)
561
+ content_tag(:option, year, :value => year, :selected => "selected") :
562
+ content_tag(:option, year, :value => year)
544
563
  )
564
+ year_options << "\n"
545
565
  end
546
- select_html(options[:field_name] || 'year', year_options.join, options)
566
+ select_html(options[:field_name] || 'year', year_options.join, options, html_options)
547
567
  end
548
568
  end
549
569
 
550
570
  private
551
571
 
552
- def select_html(type, html_options, options)
572
+ def select_html(type, html_options, options, select_tag_options = {})
553
573
  name_and_id_from_options(options, type)
554
- select_html = %(<select id="#{options[:id]}" name="#{options[:name]}")
555
- select_html << %( disabled="disabled") if options[:disabled]
556
- select_html << %(>\n)
557
- select_html << %(<option value=""></option>\n) if options[:include_blank]
574
+ select_options = {:id => options[:id], :name => options[:name]}
575
+ select_options.merge!(:disabled => 'disabled') if options[:disabled]
576
+ select_options.merge!(select_tag_options) unless select_tag_options.empty?
577
+ select_html = "\n"
578
+ select_html << content_tag(:option, '', :value => '') + "\n" if options[:include_blank]
558
579
  select_html << html_options.to_s
559
- select_html << "</select>\n"
580
+ content_tag(:select, select_html, select_options) + "\n"
560
581
  end
561
582
 
562
583
  def hidden_html(type, value, options)
563
584
  name_and_id_from_options(options, type)
564
- hidden_html = %(<input type="hidden" id="#{options[:id]}" name="#{options[:name]}" value="#{value}" />\n)
585
+ hidden_html = tag(:input, :type => "hidden", :id => options[:id], :name => options[:name], :value => value) + "\n"
565
586
  end
566
587
 
567
588
  def name_and_id_from_options(options, type)
@@ -577,20 +598,20 @@ module ActionView
577
598
  class InstanceTag #:nodoc:
578
599
  include DateHelper
579
600
 
580
- def to_date_select_tag(options = {})
581
- date_or_time_select(options.merge(:discard_hour => true))
601
+ def to_date_select_tag(options = {}, html_options = {})
602
+ date_or_time_select(options.merge(:discard_hour => true), html_options)
582
603
  end
583
604
 
584
- def to_time_select_tag(options = {})
585
- date_or_time_select options.merge(:discard_year => true, :discard_month => true)
605
+ def to_time_select_tag(options = {}, html_options = {})
606
+ date_or_time_select(options.merge(:discard_year => true, :discard_month => true), html_options)
586
607
  end
587
608
 
588
- def to_datetime_select_tag(options = {})
589
- date_or_time_select options
609
+ def to_datetime_select_tag(options = {}, html_options = {})
610
+ date_or_time_select(options, html_options)
590
611
  end
591
612
 
592
613
  private
593
- def date_or_time_select(options)
614
+ def date_or_time_select(options, html_options = {})
594
615
  defaults = { :discard_type => true }
595
616
  options = defaults.merge(options)
596
617
  datetime = value(object)
@@ -627,7 +648,7 @@ module ActionView
627
648
  # This ensures AR can reconstruct valid dates using ParseDate
628
649
  next if discard[param] && date_or_time_select.empty?
629
650
 
630
- date_or_time_select.insert(0, self.send("select_#{param}", datetime, options_with_prefix(position[param], options.merge(:use_hidden => discard[param]))))
651
+ date_or_time_select.insert(0, self.send("select_#{param}", datetime, options_with_prefix(position[param], options.merge(:use_hidden => discard[param])), html_options))
631
652
  date_or_time_select.insert(0,
632
653
  case param
633
654
  when :hour then (discard[:year] && discard[:day] ? "" : " &mdash; ")
@@ -654,7 +675,7 @@ module ActionView
654
675
  def default_time_from_options(default)
655
676
  case default
656
677
  when nil
657
- Time.now
678
+ Time.current
658
679
  when Date, Time
659
680
  default
660
681
  else
@@ -662,26 +683,27 @@ module ActionView
662
683
  default[:min] ||= default[:minute]
663
684
  default[:sec] ||= default[:second]
664
685
 
686
+ time = Time.current
687
+
665
688
  [:year, :month, :day, :hour, :min, :sec].each do |key|
666
- default[key] ||= Time.now.send(key)
689
+ default[key] ||= time.send(key)
667
690
  end
668
691
 
669
- Time.mktime(default[:year], default[:month], default[:day],
670
- default[:hour], default[:min], default[:sec])
692
+ Time.utc_time(default[:year], default[:month], default[:day], default[:hour], default[:min], default[:sec])
671
693
  end
672
694
  end
673
695
  end
674
696
 
675
697
  class FormBuilder
676
- def date_select(method, options = {})
698
+ def date_select(method, options = {}, html_options = {})
677
699
  @template.date_select(@object_name, method, options.merge(:object => @object))
678
700
  end
679
701
 
680
- def time_select(method, options = {})
702
+ def time_select(method, options = {}, html_options = {})
681
703
  @template.time_select(@object_name, method, options.merge(:object => @object))
682
704
  end
683
705
 
684
- def datetime_select(method, options = {})
706
+ def datetime_select(method, options = {}, html_options = {})
685
707
  @template.datetime_select(@object_name, method, options.merge(:object => @object))
686
708
  end
687
709
  end