actionpack 2.3.2 → 2.3.3

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 (117) hide show
  1. data/CHANGELOG +5 -0
  2. data/Rakefile +10 -9
  3. data/lib/action_controller.rb +2 -7
  4. data/lib/action_controller/assertions/response_assertions.rb +11 -3
  5. data/lib/action_controller/base.rb +7 -2
  6. data/lib/action_controller/caching.rb +1 -1
  7. data/lib/action_controller/caching/actions.rb +9 -1
  8. data/lib/action_controller/caching/sweeper.rb +45 -0
  9. data/lib/action_controller/caching/sweeping.rb +0 -42
  10. data/lib/action_controller/failsafe.rb +40 -6
  11. data/lib/action_controller/flash.rb +11 -3
  12. data/lib/action_controller/http_authentication.rb +5 -2
  13. data/lib/action_controller/integration.rb +5 -12
  14. data/lib/action_controller/middlewares.rb +0 -1
  15. data/lib/action_controller/reloader.rb +34 -3
  16. data/lib/action_controller/request.rb +6 -2
  17. data/lib/action_controller/response.rb +2 -2
  18. data/lib/action_controller/routing/route_set.rb +2 -1
  19. data/lib/action_controller/streaming.rb +1 -1
  20. data/lib/action_controller/test_process.rb +9 -1
  21. data/lib/action_pack/version.rb +1 -1
  22. data/lib/action_view/helpers.rb +1 -1
  23. data/lib/action_view/helpers/asset_tag_helper.rb +21 -9
  24. data/lib/action_view/helpers/date_helper.rb +2 -2
  25. data/lib/action_view/helpers/form_helper.rb +25 -12
  26. data/lib/action_view/helpers/form_options_helper.rb +2 -0
  27. data/lib/action_view/helpers/form_tag_helper.rb +10 -4
  28. data/lib/action_view/helpers/number_helper.rb +1 -1
  29. data/lib/action_view/helpers/prototype_helper.rb +7 -7
  30. data/lib/action_view/helpers/scriptaculous_helper.rb +5 -5
  31. data/lib/action_view/helpers/text_helper.rb +3 -3
  32. data/lib/action_view/helpers/url_helper.rb +1 -1
  33. data/lib/action_view/paths.rb +1 -1
  34. data/lib/action_view/template.rb +22 -33
  35. data/test/abstract_unit.rb +1 -1
  36. data/test/activerecord/active_record_store_test.rb +3 -3
  37. data/test/controller/action_pack_assertions_test.rb +27 -0
  38. data/test/controller/caching_test.rb +39 -0
  39. data/test/controller/cookie_test.rb +10 -0
  40. data/test/controller/dispatcher_test.rb +9 -7
  41. data/test/controller/failsafe_test.rb +60 -0
  42. data/test/controller/filter_params_test.rb +2 -1
  43. data/test/controller/flash_test.rb +6 -1
  44. data/test/controller/http_digest_authentication_test.rb +34 -3
  45. data/test/controller/integration_test.rb +31 -3
  46. data/test/controller/redirect_test.rb +4 -1
  47. data/test/controller/reloader_test.rb +97 -0
  48. data/test/controller/render_test.rb +19 -9
  49. data/test/controller/request/multipart_params_parsing_test.rb +1 -62
  50. data/test/controller/request/test_request_test.rb +35 -0
  51. data/test/controller/request/url_encoded_params_parsing_test.rb +0 -38
  52. data/test/controller/request_test.rb +218 -230
  53. data/test/controller/resources_test.rb +8 -0
  54. data/test/controller/routing_test.rb +21 -0
  55. data/test/controller/send_file_test.rb +1 -1
  56. data/test/controller/session/cookie_store_test.rb +9 -32
  57. data/test/controller/test_test.rb +8 -0
  58. data/test/fixtures/failsafe/500.html +1 -0
  59. data/test/template/active_record_helper_test.rb +1 -1
  60. data/test/template/asset_tag_helper_test.rb +46 -0
  61. data/test/template/form_helper_test.rb +117 -6
  62. data/test/template/form_options_helper_test.rb +22 -0
  63. data/test/template/form_tag_helper_test.rb +23 -6
  64. data/test/template/prototype_helper_test.rb +11 -11
  65. data/test/template/template_test.rb +32 -0
  66. metadata +20 -63
  67. data/lib/action_controller/rewindable_input.rb +0 -28
  68. data/lib/action_controller/vendor/rack-1.0/rack.rb +0 -89
  69. data/lib/action_controller/vendor/rack-1.0/rack/adapter/camping.rb +0 -22
  70. data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/handler.rb +0 -37
  71. data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/request.rb +0 -37
  72. data/lib/action_controller/vendor/rack-1.0/rack/auth/basic.rb +0 -58
  73. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/md5.rb +0 -124
  74. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/nonce.rb +0 -51
  75. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/params.rb +0 -55
  76. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/request.rb +0 -40
  77. data/lib/action_controller/vendor/rack-1.0/rack/auth/openid.rb +0 -480
  78. data/lib/action_controller/vendor/rack-1.0/rack/builder.rb +0 -63
  79. data/lib/action_controller/vendor/rack-1.0/rack/cascade.rb +0 -36
  80. data/lib/action_controller/vendor/rack-1.0/rack/chunked.rb +0 -49
  81. data/lib/action_controller/vendor/rack-1.0/rack/commonlogger.rb +0 -61
  82. data/lib/action_controller/vendor/rack-1.0/rack/conditionalget.rb +0 -45
  83. data/lib/action_controller/vendor/rack-1.0/rack/content_length.rb +0 -29
  84. data/lib/action_controller/vendor/rack-1.0/rack/content_type.rb +0 -23
  85. data/lib/action_controller/vendor/rack-1.0/rack/deflater.rb +0 -85
  86. data/lib/action_controller/vendor/rack-1.0/rack/directory.rb +0 -153
  87. data/lib/action_controller/vendor/rack-1.0/rack/file.rb +0 -88
  88. data/lib/action_controller/vendor/rack-1.0/rack/handler.rb +0 -48
  89. data/lib/action_controller/vendor/rack-1.0/rack/handler/cgi.rb +0 -61
  90. data/lib/action_controller/vendor/rack-1.0/rack/handler/evented_mongrel.rb +0 -8
  91. data/lib/action_controller/vendor/rack-1.0/rack/handler/fastcgi.rb +0 -89
  92. data/lib/action_controller/vendor/rack-1.0/rack/handler/lsws.rb +0 -55
  93. data/lib/action_controller/vendor/rack-1.0/rack/handler/mongrel.rb +0 -84
  94. data/lib/action_controller/vendor/rack-1.0/rack/handler/scgi.rb +0 -59
  95. data/lib/action_controller/vendor/rack-1.0/rack/handler/swiftiplied_mongrel.rb +0 -8
  96. data/lib/action_controller/vendor/rack-1.0/rack/handler/thin.rb +0 -18
  97. data/lib/action_controller/vendor/rack-1.0/rack/handler/webrick.rb +0 -67
  98. data/lib/action_controller/vendor/rack-1.0/rack/head.rb +0 -19
  99. data/lib/action_controller/vendor/rack-1.0/rack/lint.rb +0 -462
  100. data/lib/action_controller/vendor/rack-1.0/rack/lobster.rb +0 -65
  101. data/lib/action_controller/vendor/rack-1.0/rack/lock.rb +0 -16
  102. data/lib/action_controller/vendor/rack-1.0/rack/methodoverride.rb +0 -27
  103. data/lib/action_controller/vendor/rack-1.0/rack/mime.rb +0 -204
  104. data/lib/action_controller/vendor/rack-1.0/rack/mock.rb +0 -160
  105. data/lib/action_controller/vendor/rack-1.0/rack/recursive.rb +0 -57
  106. data/lib/action_controller/vendor/rack-1.0/rack/reloader.rb +0 -64
  107. data/lib/action_controller/vendor/rack-1.0/rack/request.rb +0 -241
  108. data/lib/action_controller/vendor/rack-1.0/rack/response.rb +0 -179
  109. data/lib/action_controller/vendor/rack-1.0/rack/session/abstract/id.rb +0 -142
  110. data/lib/action_controller/vendor/rack-1.0/rack/session/cookie.rb +0 -91
  111. data/lib/action_controller/vendor/rack-1.0/rack/session/memcache.rb +0 -109
  112. data/lib/action_controller/vendor/rack-1.0/rack/session/pool.rb +0 -100
  113. data/lib/action_controller/vendor/rack-1.0/rack/showexceptions.rb +0 -349
  114. data/lib/action_controller/vendor/rack-1.0/rack/showstatus.rb +0 -106
  115. data/lib/action_controller/vendor/rack-1.0/rack/static.rb +0 -38
  116. data/lib/action_controller/vendor/rack-1.0/rack/urlmap.rb +0 -55
  117. data/lib/action_controller/vendor/rack-1.0/rack/utils.rb +0 -392
@@ -7,7 +7,6 @@ use "ActionController::Failsafe"
7
7
  use lambda { ActionController::Base.session_store },
8
8
  lambda { ActionController::Base.session_options }
9
9
 
10
- use "ActionController::RewindableInput"
11
10
  use "ActionController::ParamsParser"
12
11
  use "Rack::MethodOverride"
13
12
  use "Rack::Head"
@@ -1,14 +1,45 @@
1
1
  module ActionController
2
2
  class Reloader
3
+ class BodyWrapper
4
+ def initialize(body)
5
+ @body = body
6
+ end
7
+
8
+ def close
9
+ @body.close if @body.respond_to?(:close)
10
+ ensure
11
+ Dispatcher.cleanup_application
12
+ end
13
+
14
+ def method_missing(*args, &block)
15
+ @body.send(*args, &block)
16
+ end
17
+
18
+ def respond_to?(symbol, include_private = false)
19
+ symbol == :close || @body.respond_to?(symbol, include_private)
20
+ end
21
+ end
22
+
3
23
  def initialize(app)
4
24
  @app = app
5
25
  end
6
26
 
7
27
  def call(env)
8
28
  Dispatcher.reload_application
9
- @app.call(env)
10
- ensure
11
- Dispatcher.cleanup_application
29
+ status, headers, body = @app.call(env)
30
+ # We do not want to call 'cleanup_application' in an ensure block
31
+ # because the returned Rack response body may lazily generate its data. This
32
+ # is for example the case if one calls
33
+ #
34
+ # render :text => lambda { ... code here which refers to application models ... }
35
+ #
36
+ # in an ActionController.
37
+ #
38
+ # Instead, we will want to cleanup the application code after the request is
39
+ # completely finished. So we wrap the body in a BodyWrapper class so that
40
+ # when the Rack handler calls #close during the end of the request, we get to
41
+ # run our cleanup code.
42
+ [status, headers, BodyWrapper.new(body)]
12
43
  end
13
44
  end
14
45
  end
@@ -95,6 +95,10 @@ module ActionController
95
95
  end
96
96
  end
97
97
 
98
+ def media_type
99
+ content_type.to_s
100
+ end
101
+
98
102
  # Returns the accepted MIME type for the request.
99
103
  def accepts
100
104
  @accepts ||= begin
@@ -383,7 +387,7 @@ EOM
383
387
  alias_method :params, :parameters
384
388
 
385
389
  def path_parameters=(parameters) #:nodoc:
386
- @env["rack.routing_args"] = parameters
390
+ @env["action_controller.request.path_parameters"] = parameters
387
391
  @symbolized_path_parameters = @parameters = nil
388
392
  end
389
393
 
@@ -399,7 +403,7 @@ EOM
399
403
  #
400
404
  # See <tt>symbolized_path_parameters</tt> for symbolized keys.
401
405
  def path_parameters
402
- @env["rack.routing_args"] ||= {}
406
+ @env["action_controller.request.path_parameters"] ||= {}
403
407
  end
404
408
 
405
409
  # The request body is an IO input stream. If the RAW_POST_DATA environment
@@ -151,8 +151,8 @@ module ActionController # :nodoc:
151
151
  if @body.respond_to?(:call)
152
152
  @writer = lambda { |x| callback.call(x) }
153
153
  @body.call(self, self)
154
- elsif @body.is_a?(String)
155
- @body.each_line(&callback)
154
+ elsif @body.respond_to?(:to_str)
155
+ yield @body
156
156
  else
157
157
  @body.each(&callback)
158
158
  end
@@ -305,6 +305,7 @@ module ActionController
305
305
  end
306
306
 
307
307
  def add_route(path, options = {})
308
+ options.each { |k, v| options[k] = v.to_s if [:controller, :action].include?(k) && v.is_a?(Symbol) }
308
309
  route = builder.build(path, options)
309
310
  routes << route
310
311
  route
@@ -436,7 +437,7 @@ module ActionController
436
437
  def recognize(request)
437
438
  params = recognize_path(request.path, extract_request_environment(request))
438
439
  request.path_parameters = params.with_indifferent_access
439
- "#{params[:controller].camelize}Controller".constantize
440
+ "#{params[:controller].to_s.camelize}Controller".constantize
440
441
  end
441
442
 
442
443
  def recognize_path(path, environment={})
@@ -161,7 +161,7 @@ module ActionController #:nodoc:
161
161
  content_type = content_type.to_s.strip # fixes a problem with extra '\r' with some browsers
162
162
 
163
163
  headers.merge!(
164
- 'Content-Length' => options[:length],
164
+ 'Content-Length' => options[:length].to_s,
165
165
  'Content-Type' => content_type,
166
166
  'Content-Disposition' => disposition,
167
167
  'Content-Transfer-Encoding' => 'binary'
@@ -1,3 +1,4 @@
1
+ require 'rack/session/abstract/id'
1
2
  module ActionController #:nodoc:
2
3
  class TestRequest < Request #:nodoc:
3
4
  attr_accessor :cookies, :session_options
@@ -13,6 +14,8 @@ module ActionController #:nodoc:
13
14
 
14
15
  @query_parameters = {}
15
16
  @session = TestSession.new
17
+ default_rack_options = Rack::Session::Abstract::ID::DEFAULT_OPTIONS
18
+ @session_options ||= {:id => generate_sid(default_rack_options[:sidbits])}.merge(default_rack_options)
16
19
 
17
20
  initialize_default_values
18
21
  initialize_containers
@@ -110,6 +113,7 @@ module ActionController #:nodoc:
110
113
  end
111
114
 
112
115
  def recycle!
116
+ @env["action_controller.request.request_parameters"] = {}
113
117
  self.query_parameters = {}
114
118
  self.path_parameters = {}
115
119
  @headers, @request_method, @accepts, @content_type = nil, nil, nil, nil
@@ -120,6 +124,10 @@ module ActionController #:nodoc:
120
124
  end
121
125
 
122
126
  private
127
+ def generate_sid(sidbits)
128
+ "%0#{sidbits / 4}x" % rand(2**sidbits - 1)
129
+ end
130
+
123
131
  def initialize_containers
124
132
  @cookies = {}
125
133
  end
@@ -250,7 +258,7 @@ module ActionController #:nodoc:
250
258
  def cookies
251
259
  cookies = {}
252
260
  Array(headers['Set-Cookie']).each do |cookie|
253
- key, value = cookie.split(";").first.split("=")
261
+ key, value = cookie.split(";").first.split("=").map {|val| Rack::Utils.unescape(val)}
254
262
  cookies[key] = value
255
263
  end
256
264
  cookies
@@ -2,7 +2,7 @@ module ActionPack #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 2
4
4
  MINOR = 3
5
- TINY = 2
5
+ TINY = 3
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -11,7 +11,7 @@ module ActionView #:nodoc:
11
11
  autoload :FormHelper, 'action_view/helpers/form_helper'
12
12
  autoload :FormOptionsHelper, 'action_view/helpers/form_options_helper'
13
13
  autoload :FormTagHelper, 'action_view/helpers/form_tag_helper'
14
- autoload :JavascriptHelper, 'action_view/helpers/javascript_helper'
14
+ autoload :JavaScriptHelper, 'action_view/helpers/javascript_helper'
15
15
  autoload :NumberHelper, 'action_view/helpers/number_helper'
16
16
  autoload :PrototypeHelper, 'action_view/helpers/prototype_helper'
17
17
  autoload :RecordIdentificationHelper, 'action_view/helpers/record_identification_helper'
@@ -272,14 +272,17 @@ module ActionView
272
272
  # javascript_include_tag :all, :cache => true, :recursive => true
273
273
  def javascript_include_tag(*sources)
274
274
  options = sources.extract_options!.stringify_keys
275
- cache = options.delete("cache")
275
+ concat = options.delete("concat")
276
+ cache = concat || options.delete("cache")
276
277
  recursive = options.delete("recursive")
277
278
 
278
- if ActionController::Base.perform_caching && cache
279
+ if concat || (ActionController::Base.perform_caching && cache)
279
280
  joined_javascript_name = (cache == true ? "all" : cache) + ".js"
280
- joined_javascript_path = File.join(JAVASCRIPTS_DIR, joined_javascript_name)
281
+ joined_javascript_path = File.join(joined_javascript_name[/^#{File::SEPARATOR}/] ? ASSETS_DIR : JAVASCRIPTS_DIR, joined_javascript_name)
281
282
 
282
- write_asset_file_contents(joined_javascript_path, compute_javascript_paths(sources, recursive)) unless File.exists?(joined_javascript_path)
283
+ unless ActionController::Base.perform_caching && File.exists?(joined_javascript_path)
284
+ write_asset_file_contents(joined_javascript_path, compute_javascript_paths(sources, recursive))
285
+ end
283
286
  javascript_src_tag(joined_javascript_name, options)
284
287
  else
285
288
  expand_javascript_sources(sources, recursive).collect { |source| javascript_src_tag(source, options) }.join("\n")
@@ -410,16 +413,25 @@ module ActionView
410
413
  # The <tt>:recursive</tt> option is also available for caching:
411
414
  #
412
415
  # stylesheet_link_tag :all, :cache => true, :recursive => true
416
+ #
417
+ # To force concatenation (even in development mode) set <tt>:concat</tt> to true. This is useful if
418
+ # you have too many stylesheets for IE to load.
419
+ #
420
+ # stylesheet_link_tag :all, :concat => true
421
+ #
413
422
  def stylesheet_link_tag(*sources)
414
423
  options = sources.extract_options!.stringify_keys
415
- cache = options.delete("cache")
424
+ concat = options.delete("concat")
425
+ cache = concat || options.delete("cache")
416
426
  recursive = options.delete("recursive")
417
427
 
418
- if ActionController::Base.perform_caching && cache
428
+ if concat || (ActionController::Base.perform_caching && cache)
419
429
  joined_stylesheet_name = (cache == true ? "all" : cache) + ".css"
420
- joined_stylesheet_path = File.join(STYLESHEETS_DIR, joined_stylesheet_name)
430
+ joined_stylesheet_path = File.join(joined_stylesheet_name[/^#{File::SEPARATOR}/] ? ASSETS_DIR : STYLESHEETS_DIR, joined_stylesheet_name)
421
431
 
422
- write_asset_file_contents(joined_stylesheet_path, compute_stylesheet_paths(sources, recursive)) unless File.exists?(joined_stylesheet_path)
432
+ unless ActionController::Base.perform_caching && File.exists?(joined_stylesheet_path)
433
+ write_asset_file_contents(joined_stylesheet_path, compute_stylesheet_paths(sources, recursive))
434
+ end
423
435
  stylesheet_tag(joined_stylesheet_name, options)
424
436
  else
425
437
  expand_stylesheet_sources(sources, recursive).collect { |source| stylesheet_tag(source, options) }.join("\n")
@@ -679,4 +691,4 @@ module ActionView
679
691
  end
680
692
  end
681
693
  end
682
- end
694
+ end
@@ -876,8 +876,8 @@ module ActionView
876
876
  input_name_from_type(type).gsub(/([\[\(])|(\]\[)/, '_').gsub(/[\]\)]/, '')
877
877
  end
878
878
 
879
- # Given an ordering of datetime components, create the selection html
880
- # and join them with their appropriate seperators
879
+ # Given an ordering of datetime components, create the selection HTML
880
+ # and join them with their appropriate separators.
881
881
  def build_selects_from_types(order)
882
882
  select = ''
883
883
  order.reverse.each do |type|
@@ -493,7 +493,8 @@ module ActionView
493
493
  # Returns a label tag tailored for labelling an input field for a specified attribute (identified by +method+) on an object
494
494
  # assigned to the template (identified by +object+). The text of label will default to the attribute name unless you specify
495
495
  # it explicitly. Additional options on the label tag can be passed as a hash with +options+. These options will be tagged
496
- # onto the HTML as an HTML element attribute as in the example shown.
496
+ # onto the HTML as an HTML element attribute as in the example shown, except for the <tt>:value</tt> option, which is designed to
497
+ # target labels for radio_button tags (where the value is used in the ID of the input tag).
497
498
  #
498
499
  # ==== Examples
499
500
  # label(:post, :title)
@@ -505,6 +506,9 @@ module ActionView
505
506
  # label(:post, :title, "A short title", :class => "title_label")
506
507
  # # => <label for="post_title" class="title_label">A short title</label>
507
508
  #
509
+ # label(:post, :privacy, "Public Post", :value => "public")
510
+ # # => <label for="post_privacy_public">Public Post</label>
511
+ #
508
512
  def label(object_name, method, text = nil, options = {})
509
513
  InstanceTag.new(object_name, method, self, options.delete(:object)).to_label_tag(text, options)
510
514
  end
@@ -720,8 +724,9 @@ module ActionView
720
724
 
721
725
  def to_label_tag(text = nil, options = {})
722
726
  options = options.stringify_keys
727
+ tag_value = options.delete("value")
723
728
  name_and_id = options.dup
724
- add_default_name_and_id(name_and_id)
729
+ add_default_name_and_id_for_value(tag_value, name_and_id)
725
730
  options.delete("index")
726
731
  options["for"] ||= name_and_id["id"]
727
732
  content = (text.blank? ? nil : text.to_s) || method_name.humanize
@@ -753,11 +758,7 @@ module ActionView
753
758
  checked = self.class.radio_button_checked?(value(object), tag_value)
754
759
  end
755
760
  options["checked"] = "checked" if checked
756
- pretty_tag_value = tag_value.to_s.gsub(/\s/, "_").gsub(/\W/, "").downcase
757
- options["id"] ||= defined?(@auto_index) ?
758
- "#{tag_id_with_index(@auto_index)}_#{pretty_tag_value}" :
759
- "#{tag_id}_#{pretty_tag_value}"
760
- add_default_name_and_id(options)
761
+ add_default_name_and_id_for_value(tag_value, options)
761
762
  tag("input", options)
762
763
  end
763
764
 
@@ -858,6 +859,17 @@ module ActionView
858
859
  end
859
860
 
860
861
  private
862
+ def add_default_name_and_id_for_value(tag_value, options)
863
+ if tag_value
864
+ pretty_tag_value = tag_value.to_s.gsub(/\s/, "_").gsub(/\W/, "").downcase
865
+ specified_id = options["id"]
866
+ add_default_name_and_id(options)
867
+ options["id"] += "_#{pretty_tag_value}" unless specified_id
868
+ else
869
+ add_default_name_and_id(options)
870
+ end
871
+ end
872
+
861
873
  def add_default_name_and_id(options)
862
874
  if options.has_key?("index")
863
875
  options["name"] ||= tag_name_with_index(options["index"])
@@ -905,6 +917,7 @@ module ActionView
905
917
  attr_accessor :object_name, :object, :options
906
918
 
907
919
  def initialize(object_name, object, template, options, proc)
920
+ @nested_child_index = {}
908
921
  @object_name, @object, @template, @options, @proc = object_name, object, template, options, proc
909
922
  @default_options = @options ? @options.slice(:index) : {}
910
923
  if @object_name.to_s.match(/\[\]$/)
@@ -1007,7 +1020,7 @@ module ActionView
1007
1020
  explicit_child_index = args.last[:child_index] if args.last.is_a?(Hash)
1008
1021
 
1009
1022
  children.map do |child|
1010
- fields_for_nested_model("#{name}[#{explicit_child_index || nested_child_index}]", child, args, block)
1023
+ fields_for_nested_model("#{name}[#{explicit_child_index || nested_child_index(name)}]", child, args, block)
1011
1024
  end.join
1012
1025
  else
1013
1026
  fields_for_nested_model(name, explicit_object || association, args, block)
@@ -1025,9 +1038,9 @@ module ActionView
1025
1038
  end
1026
1039
  end
1027
1040
 
1028
- def nested_child_index
1029
- @nested_child_index ||= -1
1030
- @nested_child_index += 1
1041
+ def nested_child_index(name)
1042
+ @nested_child_index[name] ||= -1
1043
+ @nested_child_index[name] += 1
1031
1044
  end
1032
1045
  end
1033
1046
  end
@@ -1036,4 +1049,4 @@ module ActionView
1036
1049
  cattr_accessor :default_form_builder
1037
1050
  self.default_form_builder = ::ActionView::Helpers::FormBuilder
1038
1051
  end
1039
- end
1052
+ end
@@ -230,6 +230,8 @@ module ActionView
230
230
  #
231
231
  # NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag.
232
232
  def options_for_select(container, selected = nil)
233
+ return container if String === container
234
+
233
235
  container = container.to_a if Hash === container
234
236
  selected, disabled = extract_selected_and_disabled(selected)
235
237
 
@@ -230,6 +230,8 @@ module ActionView
230
230
  # * <tt>:rows</tt> - Specify the number of rows in the textarea
231
231
  # * <tt>:cols</tt> - Specify the number of columns in the textarea
232
232
  # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
233
+ # * <tt>:escape</tt> - By default, the contents of the text input are HTML escaped.
234
+ # If you need unescaped contents, set this to false.
233
235
  # * Any other key creates standard HTML attributes for the tag.
234
236
  #
235
237
  # ==== Examples
@@ -257,7 +259,10 @@ module ActionView
257
259
  options["cols"], options["rows"] = size.split("x") if size.respond_to?(:split)
258
260
  end
259
261
 
260
- content_tag :textarea, content, { "name" => name, "id" => name }.update(options.stringify_keys)
262
+ escape = options.key?("escape") ? options.delete("escape") : true
263
+ content = html_escape(content) if escape
264
+
265
+ content_tag :textarea, content, { "name" => name, "id" => sanitize_to_id(name) }.update(options.stringify_keys)
261
266
  end
262
267
 
263
268
  # Creates a check box form input tag.
@@ -353,7 +358,8 @@ module ActionView
353
358
  disable_with << ";#{options.delete('onclick')}" if options['onclick']
354
359
 
355
360
  options["onclick"] = "if (window.hiddenCommit) { window.hiddenCommit.setAttribute('value', this.value); }"
356
- options["onclick"] << "else { hiddenCommit = this.cloneNode(false);hiddenCommit.setAttribute('type', 'hidden');this.form.appendChild(hiddenCommit); }"
361
+ options["onclick"] << "else { hiddenCommit = document.createElement('input');hiddenCommit.type = 'hidden';"
362
+ options["onclick"] << "hiddenCommit.value = this.value;hiddenCommit.name = this.name;this.form.appendChild(hiddenCommit); }"
357
363
  options["onclick"] << "this.setAttribute('originalValue', this.value);this.disabled = true;#{disable_with};"
358
364
  options["onclick"] << "result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());"
359
365
  options["onclick"] << "if (result == false) { this.value = this.getAttribute('originalValue');this.disabled = false; }return result;"
@@ -444,10 +450,10 @@ module ActionView
444
450
  ''
445
451
  when /^post$/i, "", nil
446
452
  html_options["method"] = "post"
447
- protect_against_forgery? ? content_tag(:div, token_tag, :style => 'margin:0;padding:0') : ''
453
+ protect_against_forgery? ? content_tag(:div, token_tag, :style => 'margin:0;padding:0;display:inline') : ''
448
454
  else
449
455
  html_options["method"] = "post"
450
- content_tag(:div, tag(:input, :type => "hidden", :name => "_method", :value => method) + token_tag, :style => 'margin:0;padding:0')
456
+ content_tag(:div, tag(:input, :type => "hidden", :name => "_method", :value => method) + token_tag, :style => 'margin:0;padding:0;display:inline')
451
457
  end
452
458
  end
453
459
 
@@ -140,7 +140,7 @@ module ActionView
140
140
  # number_with_delimiter(12345678) # => 12,345,678
141
141
  # number_with_delimiter(12345678.05) # => 12,345,678.05
142
142
  # number_with_delimiter(12345678, :delimiter => ".") # => 12.345.678
143
- # number_with_delimiter(12345678, :seperator => ",") # => 12,345,678
143
+ # number_with_delimiter(12345678, :separator => ",") # => 12,345,678
144
144
  # number_with_delimiter(98765432.98, :delimiter => " ", :separator => ",")
145
145
  # # => 98 765 432,98
146
146
  #
@@ -686,7 +686,7 @@ module ActionView
686
686
  # Returns an object whose <tt>to_json</tt> evaluates to +code+. Use this to pass a literal JavaScript
687
687
  # expression as an argument to another JavaScriptGenerator method.
688
688
  def literal(code)
689
- ActiveSupport::JSON::Variable.new(code.to_s)
689
+ ::ActiveSupport::JSON::Variable.new(code.to_s)
690
690
  end
691
691
 
692
692
  # Returns a collection reference by finding it through a CSS +pattern+ in the DOM. This collection can then be
@@ -973,7 +973,7 @@ module ActionView
973
973
  def loop_on_multiple_args(method, ids)
974
974
  record(ids.size>1 ?
975
975
  "#{javascript_object_for(ids)}.each(#{method})" :
976
- "#{method}(#{ids.first.to_json})")
976
+ "#{method}(#{::ActiveSupport::JSON.encode(ids.first)})")
977
977
  end
978
978
 
979
979
  def page
@@ -997,7 +997,7 @@ module ActionView
997
997
  end
998
998
 
999
999
  def javascript_object_for(object)
1000
- object.respond_to?(:to_json) ? object.to_json : object.inspect
1000
+ ::ActiveSupport::JSON.encode(object)
1001
1001
  end
1002
1002
 
1003
1003
  def arguments_for_call(arguments, block = nil)
@@ -1139,7 +1139,7 @@ module ActionView
1139
1139
  class JavaScriptElementProxy < JavaScriptProxy #:nodoc:
1140
1140
  def initialize(generator, id)
1141
1141
  @id = id
1142
- super(generator, "$(#{id.to_json})")
1142
+ super(generator, "$(#{::ActiveSupport::JSON.encode(id)})")
1143
1143
  end
1144
1144
 
1145
1145
  # Allows access of element attributes through +attribute+. Examples:
@@ -1211,7 +1211,7 @@ module ActionView
1211
1211
  enumerate :eachSlice, :variable => variable, :method_args => [number], :yield_args => %w(value index), :return => true, &block
1212
1212
  else
1213
1213
  add_variable_assignment!(variable)
1214
- append_enumerable_function!("eachSlice(#{number.to_json});")
1214
+ append_enumerable_function!("eachSlice(#{::ActiveSupport::JSON.encode(number)});")
1215
1215
  end
1216
1216
  end
1217
1217
 
@@ -1232,7 +1232,7 @@ module ActionView
1232
1232
 
1233
1233
  def pluck(variable, property)
1234
1234
  add_variable_assignment!(variable)
1235
- append_enumerable_function!("pluck(#{property.to_json});")
1235
+ append_enumerable_function!("pluck(#{::ActiveSupport::JSON.encode(property)});")
1236
1236
  end
1237
1237
 
1238
1238
  def zip(variable, *arguments, &block)
@@ -1296,7 +1296,7 @@ module ActionView
1296
1296
 
1297
1297
  class JavaScriptElementCollectionProxy < JavaScriptCollectionProxy #:nodoc:\
1298
1298
  def initialize(generator, pattern)
1299
- super(generator, "$$(#{pattern.to_json})")
1299
+ super(generator, "$$(#{::ActiveSupport::JSON.encode(pattern)})")
1300
1300
  end
1301
1301
  end
1302
1302
  end