actionpack 1.9.1 → 1.10.1

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 (123) hide show
  1. data/CHANGELOG +237 -0
  2. data/README +12 -12
  3. data/lib/action_controller.rb +17 -12
  4. data/lib/action_controller/assertions.rb +119 -67
  5. data/lib/action_controller/base.rb +184 -102
  6. data/lib/action_controller/benchmarking.rb +35 -6
  7. data/lib/action_controller/caching.rb +115 -58
  8. data/lib/action_controller/cgi_ext/cgi_methods.rb +54 -21
  9. data/lib/action_controller/cgi_ext/cookie_performance_fix.rb +39 -35
  10. data/lib/action_controller/cgi_ext/raw_post_data_fix.rb +34 -21
  11. data/lib/action_controller/cgi_process.rb +23 -20
  12. data/lib/action_controller/components.rb +11 -2
  13. data/lib/action_controller/dependencies.rb +0 -5
  14. data/lib/action_controller/deprecated_redirects.rb +17 -0
  15. data/lib/action_controller/filters.rb +13 -9
  16. data/lib/action_controller/flash.rb +7 -7
  17. data/lib/action_controller/helpers.rb +1 -14
  18. data/lib/action_controller/layout.rb +40 -29
  19. data/lib/action_controller/macros/auto_complete.rb +52 -0
  20. data/lib/action_controller/macros/in_place_editing.rb +32 -0
  21. data/lib/action_controller/pagination.rb +44 -28
  22. data/lib/action_controller/request.rb +54 -40
  23. data/lib/action_controller/rescue.rb +8 -6
  24. data/lib/action_controller/routing.rb +77 -28
  25. data/lib/action_controller/scaffolding.rb +10 -14
  26. data/lib/action_controller/session/active_record_store.rb +36 -7
  27. data/lib/action_controller/session_management.rb +126 -0
  28. data/lib/action_controller/streaming.rb +14 -5
  29. data/lib/action_controller/templates/rescues/_request_and_response.rhtml +1 -1
  30. data/lib/action_controller/templates/rescues/_trace.rhtml +24 -0
  31. data/lib/action_controller/templates/rescues/diagnostics.rhtml +2 -13
  32. data/lib/action_controller/templates/rescues/template_error.rhtml +4 -2
  33. data/lib/action_controller/templates/scaffolds/list.rhtml +1 -1
  34. data/lib/action_controller/test_process.rb +35 -17
  35. data/lib/action_controller/upload_progress.rb +52 -0
  36. data/lib/action_controller/url_rewriter.rb +21 -16
  37. data/lib/action_controller/vendor/html-scanner/html/document.rb +2 -2
  38. data/lib/action_controller/vendor/html-scanner/html/node.rb +30 -3
  39. data/lib/action_pack/version.rb +9 -0
  40. data/lib/action_view.rb +1 -1
  41. data/lib/action_view/base.rb +204 -60
  42. data/lib/action_view/compiled_templates.rb +70 -0
  43. data/lib/action_view/helpers/active_record_helper.rb +7 -3
  44. data/lib/action_view/helpers/asset_tag_helper.rb +22 -12
  45. data/lib/action_view/helpers/capture_helper.rb +2 -10
  46. data/lib/action_view/helpers/date_helper.rb +21 -13
  47. data/lib/action_view/helpers/form_helper.rb +14 -10
  48. data/lib/action_view/helpers/form_options_helper.rb +4 -4
  49. data/lib/action_view/helpers/form_tag_helper.rb +59 -25
  50. data/lib/action_view/helpers/java_script_macros_helper.rb +188 -0
  51. data/lib/action_view/helpers/javascript_helper.rb +68 -133
  52. data/lib/action_view/helpers/javascripts/controls.js +427 -165
  53. data/lib/action_view/helpers/javascripts/dragdrop.js +256 -277
  54. data/lib/action_view/helpers/javascripts/effects.js +766 -277
  55. data/lib/action_view/helpers/javascripts/prototype.js +906 -218
  56. data/lib/action_view/helpers/javascripts/slider.js +258 -0
  57. data/lib/action_view/helpers/number_helper.rb +4 -3
  58. data/lib/action_view/helpers/pagination_helper.rb +42 -27
  59. data/lib/action_view/helpers/tag_helper.rb +25 -11
  60. data/lib/action_view/helpers/text_helper.rb +119 -13
  61. data/lib/action_view/helpers/upload_progress_helper.rb +2 -2
  62. data/lib/action_view/helpers/url_helper.rb +68 -21
  63. data/lib/action_view/partials.rb +17 -6
  64. data/lib/action_view/template_error.rb +19 -24
  65. data/rakefile +4 -3
  66. data/test/abstract_unit.rb +2 -1
  67. data/test/controller/action_pack_assertions_test.rb +62 -2
  68. data/test/controller/active_record_assertions_test.rb +5 -6
  69. data/test/controller/active_record_store_test.rb +23 -1
  70. data/test/controller/addresses_render_test.rb +4 -0
  71. data/test/controller/{base_tests.rb → base_test.rb} +4 -3
  72. data/test/controller/benchmark_test.rb +36 -0
  73. data/test/controller/caching_filestore.rb +22 -40
  74. data/test/controller/capture_test.rb +10 -1
  75. data/test/controller/cgi_test.rb +145 -23
  76. data/test/controller/components_test.rb +50 -0
  77. data/test/controller/custom_handler_test.rb +3 -3
  78. data/test/controller/fake_controllers.rb +24 -0
  79. data/test/controller/filters_test.rb +6 -6
  80. data/test/controller/flash_test.rb +6 -6
  81. data/test/controller/fragment_store_setting_test.rb +45 -0
  82. data/test/controller/helper_test.rb +1 -3
  83. data/test/controller/new_render_test.rb +119 -7
  84. data/test/controller/redirect_test.rb +11 -1
  85. data/test/controller/render_test.rb +34 -1
  86. data/test/controller/request_test.rb +14 -5
  87. data/test/controller/routing_test.rb +238 -42
  88. data/test/controller/send_file_test.rb +11 -10
  89. data/test/controller/session_management_test.rb +94 -0
  90. data/test/controller/test_test.rb +194 -5
  91. data/test/controller/url_rewriter_test.rb +46 -0
  92. data/test/fixtures/layouts/talk_from_action.rhtml +2 -0
  93. data/test/fixtures/layouts/yield.rhtml +2 -0
  94. data/test/fixtures/multipart/binary_file +0 -0
  95. data/test/fixtures/multipart/large_text_file +10 -0
  96. data/test/fixtures/multipart/mixed_files +0 -0
  97. data/test/fixtures/multipart/single_parameter +5 -0
  98. data/test/fixtures/multipart/text_file +10 -0
  99. data/test/fixtures/test/_customer_greeting.rhtml +1 -0
  100. data/test/fixtures/test/_hash_object.rhtml +1 -0
  101. data/test/fixtures/test/_person.rhtml +2 -0
  102. data/test/fixtures/test/action_talk_to_layout.rhtml +2 -0
  103. data/test/fixtures/test/content_for.rhtml +2 -0
  104. data/test/fixtures/test/potential_conflicts.rhtml +4 -0
  105. data/test/template/active_record_helper_test.rb +15 -8
  106. data/test/template/asset_tag_helper_test.rb +40 -16
  107. data/test/template/compiled_templates_tests.rb +63 -0
  108. data/test/template/date_helper_test.rb +80 -4
  109. data/test/template/form_helper_test.rb +48 -42
  110. data/test/template/form_options_helper_test.rb +40 -40
  111. data/test/template/form_tag_helper_test.rb +21 -15
  112. data/test/template/java_script_macros_helper_test.rb +56 -0
  113. data/test/template/javascript_helper_test.rb +70 -47
  114. data/test/template/number_helper_test.rb +2 -0
  115. data/test/template/tag_helper_test.rb +9 -0
  116. data/test/template/text_helper_test.rb +146 -1
  117. data/test/template/upload_progress_helper_testx.rb +11 -147
  118. data/test/template/url_helper_test.rb +90 -22
  119. data/test/testing_sandbox.rb +26 -0
  120. metadata +37 -7
  121. data/lib/action_controller/auto_complete.rb +0 -47
  122. data/lib/action_controller/deprecated_renders_and_redirects.rb +0 -76
  123. data/lib/action_controller/session.rb +0 -14
@@ -17,8 +17,8 @@ module ActionView
17
17
  # (title is a VARCHAR column and holds "Hello World"):
18
18
  # input("post", "title") =>
19
19
  # <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" />
20
- def input(record_name, method)
21
- InstanceTag.new(record_name, method, self).to_tag
20
+ def input(record_name, method, options = {})
21
+ InstanceTag.new(record_name, method, self).to_tag(options)
22
22
  end
23
23
 
24
24
  # Returns an entire form with input tags and everything for a specified Active Record object. Example
@@ -71,7 +71,7 @@ module ActionView
71
71
  yield contents if block_given?
72
72
  contents << submit_tag(submit_value)
73
73
 
74
- content_tag('form', contents, :action => action, :method => 'post')
74
+ content_tag('form', contents, :action => action, :method => 'post', :enctype => options[:multipart] ? 'multipart/form-data': nil)
75
75
  end
76
76
 
77
77
  # Returns a string containing the error message attached to the +method+ on the +object+, if one exists.
@@ -96,6 +96,10 @@ module ActionView
96
96
  # * <tt>header_tag</tt> - Used for the header of the error div (default: h2)
97
97
  # * <tt>id</tt> - The id of the error div (default: errorExplanation)
98
98
  # * <tt>class</tt> - The class of the error div (default: errorExplanation)
99
+ #
100
+ # NOTE: This is a pre-packaged presentation of the errors with embedded strings and a certain HTML structure. If what
101
+ # you need is significantly different from the default presentation, it makes plenty of sense to access the object.errors
102
+ # instance yourself and set it up. View the source of this method to see how easy it is.
99
103
  def error_messages_for(object_name, options = {})
100
104
  options = options.symbolize_keys
101
105
  object = instance_variable_get("@#{object_name}")
@@ -18,13 +18,13 @@ module ActionView
18
18
  # <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.curenthost.com/controller/feed" />
19
19
  # auto_discovery_link_tag(:rss, {:action => "feed"}, {:title => "My RSS"}) # =>
20
20
  # <link rel="alternate" type="application/rss+xml" title="My RSS" href="http://www.curenthost.com/controller/feed" />
21
- def auto_discovery_link_tag(type = :rss, options = {}, tag_options = {})
21
+ def auto_discovery_link_tag(type = :rss, url_options = {}, tag_options = {})
22
22
  tag(
23
23
  "link",
24
- "rel" => tag_options[:rel] || "alternate",
25
- "type" => tag_options[:type] || "application/#{type}+xml",
24
+ "rel" => tag_options[:rel] || "alternate",
25
+ "type" => tag_options[:type] || "application/#{type}+xml",
26
26
  "title" => tag_options[:title] || type.to_s.upcase,
27
- "href" => url_for(options.merge(:only_path => false))
27
+ "href" => url_options.is_a?(Hash) ? url_for(url_options.merge(:only_path => false)) : url_options
28
28
  )
29
29
  end
30
30
 
@@ -46,12 +46,21 @@ module ActionView
46
46
  #
47
47
  # javascript_include_tag :defaults # =>
48
48
  # <script type="text/javascript" src="/javascripts/prototype.js"></script>
49
- # <script type="text/javascript" src="/javascripts/effects.js"></script>
50
- # <script type="text/javascript" src="/javascripts/controls.js"></script>
51
- # <script type="text/javascript" src="/javascripts/dragdrop.js"></script>
49
+ # <script type="text/javascript" src="/javascripts/scriptaculous.js"></script>
50
+ # <script type="text/javascript" src="/javascripts/application.js"></script> *see beloe
51
+ #
52
+ # If there's an <tt>application.js</tt> file in your <tt>public/javascripts</tt> directory,
53
+ # <tt>javascript_include_tag :defaults</tt> will automatically include it. This file
54
+ # facilitates the inclusion of small snippets of JavaScript code, along the lines of
55
+ # <tt>controllers/application.rb</tt> and <tt>helpers/application_helper.rb</tt>.
52
56
  def javascript_include_tag(*sources)
53
57
  options = sources.last.is_a?(Hash) ? sources.pop.stringify_keys : { }
54
- sources = ['prototype', 'effects', 'controls', 'dragdrop'] if sources.first == :defaults
58
+ if sources.first == :defaults
59
+ sources = ['prototype', 'scriptaculous']
60
+ if defined?(RAILS_ROOT) and File.exists?("#{RAILS_ROOT}/public/javascripts/application.js")
61
+ sources << 'application'
62
+ end
63
+ end
55
64
  sources.collect { |source|
56
65
  source = javascript_path(source)
57
66
  content_tag("script", "", { "type" => "text/javascript", "src" => source }.merge(options))
@@ -94,7 +103,7 @@ module ActionView
94
103
  compute_public_path(source, 'images', 'png')
95
104
  end
96
105
 
97
- # Returns an image tag converting the +options+ instead html options on the tag, but with these special cases:
106
+ # Returns an image tag converting the +options+ into html options on the tag, but with these special cases:
98
107
  #
99
108
  # * <tt>:alt</tt> - If no alt text is given, the file name part of the +src+ is used (capitalized and without the extension)
100
109
  # * <tt>:size</tt> - Supplied as "XxY", so "30x45" becomes width="30" and height="45"
@@ -119,10 +128,11 @@ module ActionView
119
128
 
120
129
  private
121
130
  def compute_public_path(source, dir, ext)
122
- source = "/#{dir}/#{source}" unless source.include?("/")
131
+ source = "/#{dir}/#{source}" unless source.first == "/" || source.include?(":")
123
132
  source = "#{source}.#{ext}" unless source.include?(".")
124
- source = "#{@request.relative_url_root}#{source}" unless %r{^[-a-z]+://} =~ source
125
- ActionController::Base.asset_host + source
133
+ source = "#{@controller.request.relative_url_root}#{source}" unless %r{^[-a-z]+://} =~ source
134
+ source = ActionController::Base.asset_host + source unless source.include?(":")
135
+ source
126
136
  end
127
137
  end
128
138
  end
@@ -81,17 +81,9 @@ module ActionView
81
81
  #
82
82
  # NOTE: Beware that content_for is ignored in caches. So you shouldn't use it
83
83
  # for elements that are going to be fragment cached.
84
- def content_for(name, &block)
85
- base = controller.instance_variable_get(instance_var_name(name)) || ""
86
- data = capture(&block)
87
- controller.instance_variable_set(instance_var_name(name), base + data)
88
- data
84
+ def content_for(name, &block)
85
+ eval "@content_for_#{name} = (@content_for_#{name} || '') + capture(&block)"
89
86
  end
90
-
91
- private
92
- def instance_var_name(name) #:nodoc#
93
- "@content_for_#{name}"
94
- end
95
87
  end
96
88
  end
97
89
  end
@@ -13,7 +13,7 @@ module ActionView
13
13
  module DateHelper
14
14
  DEFAULT_PREFIX = 'date' unless const_defined?('DEFAULT_PREFIX')
15
15
 
16
- # Reports the approximate distance in time between to Time objects or integers.
16
+ # Reports the approximate distance in time between two Time objects or integers.
17
17
  # For example, if the distance is 47 minutes, it'll return
18
18
  # "about 1 hour". See the source for the complete wording list.
19
19
  #
@@ -56,12 +56,14 @@ module ActionView
56
56
 
57
57
  # Returns a set of select tags (one for year, month, and day) pre-selected for accessing a specified date-based attribute (identified by
58
58
  # +method+) on an object assigned to the template (identified by +object+). It's possible to tailor the selects through the +options+ hash,
59
- # which both accepts all the keys that each of the individual select builders does (like :use_month_numbers for select_month) and a range of
59
+ # 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
60
60
  # discard options. The discard options are <tt>:discard_year</tt>, <tt>:discard_month</tt> and <tt>:discard_day</tt>. Set to true, they'll
61
61
  # drop the respective select. Discarding the month select will also automatically discard the day select. It's also possible to explicitly
62
62
  # 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
63
63
  # the desired order. Symbols may be omitted and the respective select is not included.
64
64
  #
65
+ # Passing :disabled => true as part of the +options+ will make elements inaccessible for change.
66
+ #
65
67
  # NOTE: Discarded selects will default to 1. So if no month select is available, January will be assumed.
66
68
  #
67
69
  # Examples:
@@ -94,7 +96,7 @@ module ActionView
94
96
  select_year(date, options) + select_month(date, options) + select_day(date, options)
95
97
  end
96
98
 
97
- # Returns a set of html select-tags (one for year, month, day, hour, and minute) preselected the +datetime+.
99
+ # Returns a set of html select-tags (one for year, month, day, hour, and minute) pre-selected with the +datetime+.
98
100
  def select_datetime(datetime = Time.now, options = {})
99
101
  select_year(datetime, options) + select_month(datetime, options) + select_day(datetime, options) +
100
102
  select_hour(datetime, options) + select_minute(datetime, options)
@@ -118,7 +120,7 @@ module ActionView
118
120
  )
119
121
  end
120
122
 
121
- select_html(options[:field_name] || 'second', second_options, options[:prefix], options[:include_blank], options[:discard_type])
123
+ select_html(options[:field_name] || 'second', second_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
122
124
  end
123
125
 
124
126
  # Returns a select tag with options for each of the minutes 0 through 59 with the current minute selected.
@@ -135,7 +137,7 @@ module ActionView
135
137
  )
136
138
  end
137
139
 
138
- select_html(options[:field_name] || 'minute', minute_options, options[:prefix], options[:include_blank], options[:discard_type])
140
+ select_html(options[:field_name] || 'minute', minute_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
139
141
  end
140
142
 
141
143
  # Returns a select tag with options for each of the hours 0 through 23 with the current hour selected.
@@ -151,7 +153,7 @@ module ActionView
151
153
  )
152
154
  end
153
155
 
154
- select_html(options[:field_name] || 'hour', hour_options, options[:prefix], options[:include_blank], options[:discard_type])
156
+ select_html(options[:field_name] || 'hour', hour_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
155
157
  end
156
158
 
157
159
  # Returns a select tag with options for each of the days 1 through 31 with the current day selected.
@@ -167,7 +169,7 @@ module ActionView
167
169
  )
168
170
  end
169
171
 
170
- select_html(options[:field_name] || 'day', day_options, options[:prefix], options[:include_blank], options[:discard_type])
172
+ select_html(options[:field_name] || 'day', day_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
171
173
  end
172
174
 
173
175
  # Returns a select tag with options for each of the months January through December with the current month selected.
@@ -181,16 +183,20 @@ module ActionView
181
183
  # select_month(Date.today, :add_month_numbers => true) # Will use keys like "1 - January", "3 - March"
182
184
  #
183
185
  # Override the field name using the <tt>:field_name</tt> option, 'month' by default.
186
+ #
187
+ # If you would prefer to show month names as abbreviations, set the
188
+ # <tt>:use_short_month</tt> key in +options+ to true.
184
189
  def select_month(date, options = {})
185
190
  month_options = []
191
+ month_names = options[:use_short_month] ? Date::ABBR_MONTHNAMES : Date::MONTHNAMES
186
192
 
187
193
  1.upto(12) do |month_number|
188
194
  month_name = if options[:use_month_numbers]
189
195
  month_number
190
196
  elsif options[:add_month_numbers]
191
- month_number.to_s + ' - ' + Date::MONTHNAMES[month_number]
197
+ month_number.to_s + ' - ' + month_names[month_number]
192
198
  else
193
- Date::MONTHNAMES[month_number]
199
+ month_names[month_number]
194
200
  end
195
201
 
196
202
  month_options << ((date && (date.kind_of?(Fixnum) ? date : date.month) == month_number) ?
@@ -199,7 +205,7 @@ module ActionView
199
205
  )
200
206
  end
201
207
 
202
- select_html(options[:field_name] || 'month', month_options, options[:prefix], options[:include_blank], options[:discard_type])
208
+ select_html(options[:field_name] || 'month', month_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
203
209
  end
204
210
 
205
211
  # Returns a select tag with options for each of the five years on each side of the current, which is selected. The five year radius
@@ -225,14 +231,16 @@ module ActionView
225
231
  )
226
232
  end
227
233
 
228
- select_html(options[:field_name] || 'year', year_options, options[:prefix], options[:include_blank], options[:discard_type])
234
+ select_html(options[:field_name] || 'year', year_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
229
235
  end
230
236
 
231
237
  private
232
- def select_html(type, options, prefix = nil, include_blank = false, discard_type = false)
238
+ def select_html(type, options, prefix = nil, include_blank = false, discard_type = false, disabled = false)
233
239
  select_html = %(<select name="#{prefix || DEFAULT_PREFIX})
234
240
  select_html << "[#{type}]" unless discard_type
235
- select_html << %(">\n)
241
+ select_html << %(")
242
+ select_html << %( disabled="disabled") if disabled
243
+ select_html << %(>\n)
236
244
  select_html << %(<option value=""></option>\n) if include_blank
237
245
  select_html << options.to_s
238
246
  select_html << "</select>\n"
@@ -35,7 +35,7 @@ module ActionView
35
35
  # size="20" maxsize="20" value="<%= @person.password %>" />
36
36
  #
37
37
  # Single?:
38
- # <input type="checkbox" id="person_single" name="person[single] value="1" />
38
+ # <input type="checkbox" id="person_single" name="person[single]" value="1" />
39
39
  #
40
40
  # Description:
41
41
  # <textarea cols="20" rows="40" id="person_description" name="person[description]">
@@ -76,17 +76,17 @@ module ActionView
76
76
  InstanceTag.new(object, method, self).to_input_field_tag("text", options)
77
77
  end
78
78
 
79
- # Works just like text_field, but returns a input tag of the "password" type instead.
79
+ # Works just like text_field, but returns an input tag of the "password" type instead.
80
80
  def password_field(object, method, options = {})
81
81
  InstanceTag.new(object, method, self).to_input_field_tag("password", options)
82
82
  end
83
83
 
84
- # Works just like text_field, but returns a input tag of the "hidden" type instead.
84
+ # Works just like text_field, but returns an input tag of the "hidden" type instead.
85
85
  def hidden_field(object, method, options = {})
86
86
  InstanceTag.new(object, method, self).to_input_field_tag("hidden", options)
87
87
  end
88
88
 
89
- # Works just like text_field, but returns a input tag of the "file" type instead, which won't have any default value.
89
+ # Works just like text_field, but returns an input tag of the "file" type instead, which won't have a default value.
90
90
  def file_field(object, method, options = {})
91
91
  InstanceTag.new(object, method, self).to_input_field_tag("file", options)
92
92
  end
@@ -113,12 +113,12 @@ module ActionView
113
113
  #
114
114
  # Example (call, result). Imagine that @post.validated? returns 1:
115
115
  # check_box("post", "validated")
116
- # <input type="checkbox" id="post_validate" name="post[validated] value="1" checked="checked" />
116
+ # <input type="checkbox" id="post_validate" name="post[validated]" value="1" checked="checked" />
117
117
  # <input name="post[validated]" type="hidden" value="0" />
118
118
  #
119
119
  # Example (call, result). Imagine that @puppy.gooddog returns no:
120
120
  # check_box("puppy", "gooddog", {}, "yes", "no")
121
- # <input type="checkbox" id="puppy_gooddog" name="puppy[gooddog] value="yes" />
121
+ # <input type="checkbox" id="puppy_gooddog" name="puppy[gooddog]" value="yes" />
122
122
  # <input name="puppy[gooddog]" type="hidden" value="no" />
123
123
  def check_box(object, method, options = {}, checked_value = "1", unchecked_value = "0")
124
124
  InstanceTag.new(object, method, self).to_check_box_tag(options, checked_value, unchecked_value)
@@ -131,8 +131,8 @@ module ActionView
131
131
  # Example (call, result). Imagine that @post.category returns "rails":
132
132
  # radio_button("post", "category", "rails")
133
133
  # radio_button("post", "category", "java")
134
- # <input type="radio" id="post_category" name="post[category] value="rails" checked="checked" />
135
- # <input type="radio" id="post_category" name="post[category] value="java" />
134
+ # <input type="radio" id="post_category" name="post[category]" value="rails" checked="checked" />
135
+ # <input type="radio" id="post_category" name="post[category]" value="java" />
136
136
  #
137
137
  def radio_button(object, method, tag_value, options = {})
138
138
  InstanceTag.new(object, method, self).to_radio_button_tag(tag_value, options)
@@ -174,7 +174,7 @@ module ActionView
174
174
  options = DEFAULT_RADIO_OPTIONS.merge(options.stringify_keys)
175
175
  options["type"] = "radio"
176
176
  options["value"] = tag_value
177
- options["checked"] = "checked" if value == tag_value
177
+ options["checked"] = "checked" if value.to_s == tag_value.to_s
178
178
  pretty_tag_value = tag_value.to_s.gsub(/\s/, "_").gsub(/\W/, "").downcase
179
179
  options["id"] = @auto_index ?
180
180
  "#{@object_name}_#{@auto_index}_#{@method_name}_#{pretty_tag_value}" :
@@ -234,7 +234,11 @@ module ActionView
234
234
  tag_text << " selected" if value
235
235
  tag_text << ">True</option></select>"
236
236
  end
237
-
237
+
238
+ def to_content_tag(tag_name, options = {})
239
+ content_tag(tag_name, value, options)
240
+ end
241
+
238
242
  def object
239
243
  @template_object.instance_variable_get "@#{@object_name}"
240
244
  end
@@ -109,7 +109,7 @@ module ActionView
109
109
  container = container.to_a if Hash === container
110
110
 
111
111
  options_for_select = container.inject([]) do |options, element|
112
- if element.respond_to?(:first) && element.respond_to?(:last)
112
+ if element.is_a?(Array) || element.is_a?(Range)
113
113
  is_selected = ( (selected.respond_to?(:include?) ? selected.include?(element.last) : element.last == selected) )
114
114
  is_selected = ( (selected.respond_to?(:include?) && !selected.is_a?(String) ? selected.include?(element.last) : element.last == selected) )
115
115
  if is_selected
@@ -127,11 +127,11 @@ module ActionView
127
127
  options_for_select.join("\n")
128
128
  end
129
129
 
130
- # Returns a string of option tags that has been compiled by iterating over the +collection+ and assigning the
130
+ # Returns a string of option tags that have been compiled by iterating over the +collection+ and assigning the
131
131
  # the result of a call to the +value_method+ as the option value and the +text_method+ as the option text.
132
132
  # If +selected_value+ is specified, the element returning a match on +value_method+ will get the selected option tag.
133
133
  #
134
- # Example (call, result). Imagine a loop iterating over each +person+ in <tt>@project.people</tt> to generate a input tag:
134
+ # Example (call, result). Imagine a loop iterating over each +person+ in <tt>@project.people</tt> to generate an input tag:
135
135
  # options_from_collection_for_select(@project.people, "id", "name")
136
136
  # <option value="#{person.id}">#{person.name}</option>
137
137
  #
@@ -143,7 +143,7 @@ module ActionView
143
143
  )
144
144
  end
145
145
 
146
- # Returns a string of option tags, like options_from_collection_for_select, but surrounds them by <optgroup> tags.
146
+ # Returns a string of option tags, like options_from_collection_for_select, but surrounds them with <optgroup> tags.
147
147
  #
148
148
  # An array of group objects are passed. Each group should return an array of options when calling group_method
149
149
  # Each group should should return its name when calling group_label_method.
@@ -6,7 +6,7 @@ module ActionView
6
6
  # Provides a number of methods for creating form tags that doesn't rely on conventions with an object assigned to the template like
7
7
  # FormHelper does. With the FormTagHelper, you provide the names and values yourself.
8
8
  #
9
- # NOTE: The html options disabled, readonly, and multiple can all be treated as booleans. So specifying <tt>disabled => :true</tt>
9
+ # NOTE: The html options disabled, readonly, and multiple can all be treated as booleans. So specifying <tt>:disabled => true</tt>
10
10
  # will give <tt>disabled="disabled"</tt>.
11
11
  module FormTagHelper
12
12
  # Starts a form tag that points the action to an url configured with <tt>url_for_options</tt> just like
@@ -14,6 +14,7 @@ module ActionView
14
14
  #
15
15
  # Options:
16
16
  # * <tt>:multipart</tt> - If set to true, the enctype is set to "multipart/form-data".
17
+ # * <tt>:method</tt> - The method to use when submitting the form, usually either "get" or "post".
17
18
  def form_tag(url_for_options = {}, options = {}, *parameters_for_url)
18
19
  html_options = { "method" => "post" }.merge(options.stringify_keys)
19
20
 
@@ -33,26 +34,68 @@ module ActionView
33
34
  "</form>"
34
35
  end
35
36
 
37
+ # Creates a dropdown selection box, or if the <tt>:multiple</tt> option is set to true, a multiple
38
+ # choice selection box.
39
+ #
40
+ # Helpers::FormOptions can be used to create common select boxes such as countries, time zones, or
41
+ # associated records.
42
+ #
43
+ # <tt>option_tags</tt> is a string containing the option tags for the select box:
44
+ # # Outputs <select id="people" name="people"><option>David</option></select>
45
+ # select_tag "people", "<option>David</option>"
46
+ #
47
+ # Options:
48
+ # * <tt>:multiple</tt> - If set to true the selection will allow multiple choices.
36
49
  def select_tag(name, option_tags = nil, options = {})
37
- content_tag("select", option_tags, { "name" => name, "id" => name }.update(convert_options(options)))
50
+ content_tag("select", option_tags, { "name" => name, "id" => name }.update(options.stringify_keys))
38
51
  end
39
52
 
53
+ # Creates a standard text field.
54
+ #
55
+ # Options:
56
+ # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
57
+ # * <tt>:size</tt> - The number of visible characters that will fit in the input.
58
+ # * <tt>:maxlength</tt> - The maximum number of characters that the browser will allow the user to enter.
59
+ #
60
+ # A hash of standard HTML options for the tag.
40
61
  def text_field_tag(name, value = nil, options = {})
41
- tag("input", { "type" => "text", "name" => name, "id" => name, "value" => value }.update(convert_options(options)))
62
+ tag("input", { "type" => "text", "name" => name, "id" => name, "value" => value }.update(options.stringify_keys))
42
63
  end
43
64
 
65
+ # Creates a hidden field.
66
+ #
67
+ # Takes the same options as text_field_tag
44
68
  def hidden_field_tag(name, value = nil, options = {})
45
69
  text_field_tag(name, value, options.stringify_keys.update("type" => "hidden"))
46
70
  end
47
71
 
72
+ # Creates a file upload field.
73
+ #
74
+ # If you are using file uploads then you will also need to set the multipart option for the form:
75
+ # <%= form_tag { :action => "post" }, { :multipart => true } %>
76
+ # <label for="file">File to Upload</label> <%= file_field_tag "file" %>
77
+ # <%= submit_tag %>
78
+ # <%= end_form_tag %>
79
+ #
80
+ # The specified URL will then be passed a File object containing the selected file, or if the field
81
+ # was left blank, a StringIO object.
48
82
  def file_field_tag(name, options = {})
49
- text_field_tag(name, nil, convert_options(options).update("type" => "file"))
83
+ text_field_tag(name, nil, options.update("type" => "file"))
50
84
  end
51
85
 
86
+ # Creates a password field.
87
+ #
88
+ # Takes the same options as text_field_tag
52
89
  def password_field_tag(name = "password", value = nil, options = {})
53
- text_field_tag(name, value, convert_options(options).update("type" => "password"))
90
+ text_field_tag(name, value, options.update("type" => "password"))
54
91
  end
55
92
 
93
+ # Creates a text input area.
94
+ #
95
+ # Options:
96
+ # * <tt>:size</tt> - A string specifying the dimensions of the textarea.
97
+ # # Outputs <textarea name="body" id="body" cols="25" rows="10"></textarea>
98
+ # <%= text_area_tag "body", nil, :size => 25x10 %>
56
99
  def text_area_tag(name, content = nil, options = {})
57
100
  options = options.stringify_keys
58
101
  if options["size"]
@@ -60,43 +103,34 @@ module ActionView
60
103
  options.delete("size")
61
104
  end
62
105
 
63
- content_tag("textarea", content, { "name" => name, "id" => name }.update(convert_options(options)))
106
+ content_tag("textarea", content, { "name" => name, "id" => name }.update(options.stringify_keys))
64
107
  end
65
108
 
109
+ # Creates a check box.
66
110
  def check_box_tag(name, value = "1", checked = false, options = {})
67
- html_options = { "type" => "checkbox", "name" => name, "id" => name, "value" => value }.update(convert_options(options))
111
+ html_options = { "type" => "checkbox", "name" => name, "id" => name, "value" => value }.update(options.stringify_keys)
68
112
  html_options["checked"] = "checked" if checked
69
113
  tag("input", html_options)
70
114
  end
71
115
 
116
+ # Creates a radio button.
72
117
  def radio_button_tag(name, value, checked = false, options = {})
73
- html_options = { "type" => "radio", "name" => name, "id" => name, "value" => value }.update(convert_options(options))
118
+ html_options = { "type" => "radio", "name" => name, "id" => name, "value" => value }.update(options.stringify_keys)
74
119
  html_options["checked"] = "checked" if checked
75
120
  tag("input", html_options)
76
121
  end
77
122
 
123
+ # Creates a submit button with the text <tt>value</tt> as the caption.
78
124
  def submit_tag(value = "Save changes", options = {})
79
- tag("input", { "type" => "submit", "name" => "commit", "value" => value }.update(convert_options(options)))
125
+ tag("input", { "type" => "submit", "name" => "commit", "value" => value }.update(options.stringify_keys))
80
126
  end
81
127
 
128
+ # Displays an image which when clicked will submit the form.
129
+ #
130
+ # <tt>source</tt> is passed to AssetTagHelper#image_path
82
131
  def image_submit_tag(source, options = {})
83
- tag("input", { "type" => "image", "src" => image_path(source) }.update(convert_options(options)))
132
+ tag("input", { "type" => "image", "src" => image_path(source) }.update(options.stringify_keys))
84
133
  end
85
-
86
- private
87
- def convert_options(options)
88
- options = options.stringify_keys
89
- %w( disabled readonly multiple ).each { |a| boolean_attribute(options, a) }
90
- options
91
- end
92
-
93
- def boolean_attribute(options, attribute)
94
- if options[attribute]
95
- options[attribute] = attribute
96
- else
97
- options.delete attribute
98
- end
99
- end
100
134
  end
101
135
  end
102
136
  end