actionpack 2.2.3 → 2.3.2

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 (264) hide show
  1. data/CHANGELOG +433 -375
  2. data/MIT-LICENSE +1 -1
  3. data/README +21 -75
  4. data/Rakefile +1 -1
  5. data/lib/action_controller.rb +80 -43
  6. data/lib/action_controller/assertions/model_assertions.rb +1 -0
  7. data/lib/action_controller/assertions/response_assertions.rb +43 -16
  8. data/lib/action_controller/assertions/routing_assertions.rb +1 -1
  9. data/lib/action_controller/assertions/selector_assertions.rb +17 -12
  10. data/lib/action_controller/assertions/tag_assertions.rb +1 -4
  11. data/lib/action_controller/base.rb +153 -82
  12. data/lib/action_controller/benchmarking.rb +9 -9
  13. data/lib/action_controller/caching.rb +9 -11
  14. data/lib/action_controller/caching/actions.rb +11 -18
  15. data/lib/action_controller/caching/fragments.rb +28 -20
  16. data/lib/action_controller/caching/pages.rb +13 -15
  17. data/lib/action_controller/caching/sweeping.rb +2 -2
  18. data/lib/action_controller/cgi_ext.rb +0 -1
  19. data/lib/action_controller/cgi_ext/cookie.rb +2 -0
  20. data/lib/action_controller/cgi_process.rb +54 -162
  21. data/lib/action_controller/cookies.rb +13 -25
  22. data/lib/action_controller/dispatcher.rb +43 -122
  23. data/lib/action_controller/failsafe.rb +52 -0
  24. data/lib/action_controller/flash.rb +38 -47
  25. data/lib/action_controller/helpers.rb +13 -9
  26. data/lib/action_controller/http_authentication.rb +203 -23
  27. data/lib/action_controller/integration.rb +126 -70
  28. data/lib/action_controller/layout.rb +36 -39
  29. data/lib/action_controller/middleware_stack.rb +119 -0
  30. data/lib/action_controller/middlewares.rb +13 -0
  31. data/lib/action_controller/mime_responds.rb +19 -4
  32. data/lib/action_controller/mime_type.rb +8 -0
  33. data/lib/action_controller/params_parser.rb +71 -0
  34. data/lib/action_controller/performance_test.rb +0 -1
  35. data/lib/action_controller/polymorphic_routes.rb +36 -30
  36. data/lib/action_controller/reloader.rb +14 -0
  37. data/lib/action_controller/request.rb +107 -499
  38. data/lib/action_controller/request_forgery_protection.rb +7 -39
  39. data/lib/action_controller/rescue.rb +55 -35
  40. data/lib/action_controller/resources.rb +34 -31
  41. data/lib/action_controller/response.rb +99 -57
  42. data/lib/action_controller/rewindable_input.rb +28 -0
  43. data/lib/action_controller/routing.rb +7 -7
  44. data/lib/action_controller/routing/builder.rb +4 -1
  45. data/lib/action_controller/routing/optimisations.rb +1 -1
  46. data/lib/action_controller/routing/recognition_optimisation.rb +1 -2
  47. data/lib/action_controller/routing/route.rb +15 -5
  48. data/lib/action_controller/routing/route_set.rb +82 -35
  49. data/lib/action_controller/routing/segments.rb +35 -0
  50. data/lib/action_controller/session/abstract_store.rb +181 -0
  51. data/lib/action_controller/session/cookie_store.rb +197 -175
  52. data/lib/action_controller/session/mem_cache_store.rb +36 -83
  53. data/lib/action_controller/session_management.rb +26 -134
  54. data/lib/action_controller/streaming.rb +24 -7
  55. data/lib/action_controller/templates/rescues/diagnostics.erb +2 -2
  56. data/lib/action_controller/templates/rescues/template_error.erb +2 -2
  57. data/lib/action_controller/test_case.rb +87 -30
  58. data/lib/action_controller/test_process.rb +145 -104
  59. data/lib/action_controller/uploaded_file.rb +44 -0
  60. data/lib/action_controller/url_rewriter.rb +3 -6
  61. data/lib/action_controller/vendor/html-scanner.rb +16 -0
  62. data/lib/action_controller/vendor/html-scanner/html/selector.rb +1 -1
  63. data/lib/action_controller/vendor/rack-1.0/rack.rb +89 -0
  64. data/lib/action_controller/vendor/rack-1.0/rack/adapter/camping.rb +22 -0
  65. data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/handler.rb +37 -0
  66. data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/request.rb +37 -0
  67. data/lib/action_controller/vendor/rack-1.0/rack/auth/basic.rb +58 -0
  68. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/md5.rb +124 -0
  69. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/nonce.rb +51 -0
  70. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/params.rb +55 -0
  71. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/request.rb +40 -0
  72. data/lib/action_controller/vendor/rack-1.0/rack/auth/openid.rb +480 -0
  73. data/lib/action_controller/vendor/rack-1.0/rack/builder.rb +63 -0
  74. data/lib/action_controller/vendor/rack-1.0/rack/cascade.rb +36 -0
  75. data/lib/action_controller/vendor/rack-1.0/rack/chunked.rb +49 -0
  76. data/lib/action_controller/vendor/rack-1.0/rack/commonlogger.rb +61 -0
  77. data/lib/action_controller/vendor/rack-1.0/rack/conditionalget.rb +45 -0
  78. data/lib/action_controller/vendor/rack-1.0/rack/content_length.rb +29 -0
  79. data/lib/action_controller/vendor/rack-1.0/rack/content_type.rb +23 -0
  80. data/lib/action_controller/vendor/rack-1.0/rack/deflater.rb +85 -0
  81. data/lib/action_controller/vendor/rack-1.0/rack/directory.rb +153 -0
  82. data/lib/action_controller/vendor/rack-1.0/rack/file.rb +88 -0
  83. data/lib/action_controller/vendor/rack-1.0/rack/handler.rb +48 -0
  84. data/lib/action_controller/vendor/rack-1.0/rack/handler/cgi.rb +61 -0
  85. data/lib/action_controller/vendor/rack-1.0/rack/handler/evented_mongrel.rb +8 -0
  86. data/lib/action_controller/vendor/rack-1.0/rack/handler/fastcgi.rb +89 -0
  87. data/lib/action_controller/vendor/rack-1.0/rack/handler/lsws.rb +55 -0
  88. data/lib/action_controller/vendor/rack-1.0/rack/handler/mongrel.rb +84 -0
  89. data/lib/action_controller/vendor/rack-1.0/rack/handler/scgi.rb +59 -0
  90. data/lib/action_controller/vendor/rack-1.0/rack/handler/swiftiplied_mongrel.rb +8 -0
  91. data/lib/action_controller/vendor/rack-1.0/rack/handler/thin.rb +18 -0
  92. data/lib/action_controller/vendor/rack-1.0/rack/handler/webrick.rb +67 -0
  93. data/lib/action_controller/vendor/rack-1.0/rack/head.rb +19 -0
  94. data/lib/action_controller/vendor/rack-1.0/rack/lint.rb +462 -0
  95. data/lib/action_controller/vendor/rack-1.0/rack/lobster.rb +65 -0
  96. data/lib/action_controller/vendor/rack-1.0/rack/lock.rb +16 -0
  97. data/lib/action_controller/vendor/rack-1.0/rack/methodoverride.rb +27 -0
  98. data/lib/action_controller/vendor/rack-1.0/rack/mime.rb +204 -0
  99. data/lib/action_controller/vendor/rack-1.0/rack/mock.rb +160 -0
  100. data/lib/action_controller/vendor/rack-1.0/rack/recursive.rb +57 -0
  101. data/lib/action_controller/vendor/rack-1.0/rack/reloader.rb +64 -0
  102. data/lib/action_controller/vendor/rack-1.0/rack/request.rb +241 -0
  103. data/lib/action_controller/vendor/rack-1.0/rack/response.rb +179 -0
  104. data/lib/action_controller/vendor/rack-1.0/rack/session/abstract/id.rb +142 -0
  105. data/lib/action_controller/vendor/rack-1.0/rack/session/cookie.rb +91 -0
  106. data/lib/action_controller/vendor/rack-1.0/rack/session/memcache.rb +109 -0
  107. data/lib/action_controller/vendor/rack-1.0/rack/session/pool.rb +100 -0
  108. data/lib/action_controller/vendor/rack-1.0/rack/showexceptions.rb +349 -0
  109. data/lib/action_controller/vendor/rack-1.0/rack/showstatus.rb +106 -0
  110. data/lib/action_controller/vendor/rack-1.0/rack/static.rb +38 -0
  111. data/lib/action_controller/vendor/rack-1.0/rack/urlmap.rb +55 -0
  112. data/lib/action_controller/vendor/rack-1.0/rack/utils.rb +392 -0
  113. data/lib/action_controller/verification.rb +1 -1
  114. data/lib/action_pack.rb +1 -1
  115. data/lib/action_pack/version.rb +2 -2
  116. data/lib/action_view.rb +22 -17
  117. data/lib/action_view/base.rb +53 -79
  118. data/lib/action_view/erb/util.rb +38 -0
  119. data/lib/action_view/helpers.rb +24 -5
  120. data/lib/action_view/helpers/active_record_helper.rb +2 -2
  121. data/lib/action_view/helpers/asset_tag_helper.rb +81 -50
  122. data/lib/action_view/helpers/atom_feed_helper.rb +1 -1
  123. data/lib/action_view/helpers/benchmark_helper.rb +26 -5
  124. data/lib/action_view/helpers/date_helper.rb +82 -7
  125. data/lib/action_view/helpers/form_helper.rb +295 -64
  126. data/lib/action_view/helpers/form_options_helper.rb +160 -18
  127. data/lib/action_view/helpers/form_tag_helper.rb +2 -2
  128. data/lib/action_view/helpers/number_helper.rb +31 -18
  129. data/lib/action_view/helpers/prototype_helper.rb +2 -12
  130. data/lib/action_view/helpers/sanitize_helper.rb +0 -10
  131. data/lib/action_view/helpers/scriptaculous_helper.rb +1 -0
  132. data/lib/action_view/helpers/tag_helper.rb +3 -4
  133. data/lib/action_view/helpers/text_helper.rb +99 -122
  134. data/lib/action_view/helpers/translation_helper.rb +19 -1
  135. data/lib/action_view/helpers/url_helper.rb +25 -2
  136. data/lib/action_view/inline_template.rb +1 -1
  137. data/lib/action_view/locale/en.yml +19 -1
  138. data/lib/action_view/partials.rb +46 -9
  139. data/lib/action_view/paths.rb +28 -84
  140. data/lib/action_view/reloadable_template.rb +117 -0
  141. data/lib/action_view/renderable.rb +28 -35
  142. data/lib/action_view/renderable_partial.rb +3 -4
  143. data/lib/action_view/template.rb +172 -31
  144. data/lib/action_view/template_error.rb +8 -9
  145. data/lib/action_view/template_handler.rb +1 -1
  146. data/lib/action_view/template_handlers.rb +9 -6
  147. data/lib/action_view/template_handlers/erb.rb +2 -39
  148. data/lib/action_view/template_handlers/rjs.rb +1 -0
  149. data/lib/action_view/test_case.rb +27 -1
  150. data/test/abstract_unit.rb +23 -17
  151. data/test/active_record_unit.rb +5 -4
  152. data/test/activerecord/active_record_store_test.rb +139 -106
  153. data/test/activerecord/render_partial_with_record_identification_test.rb +5 -21
  154. data/test/controller/action_pack_assertions_test.rb +25 -23
  155. data/test/controller/addresses_render_test.rb +3 -6
  156. data/test/controller/assert_select_test.rb +83 -70
  157. data/test/controller/base_test.rb +11 -13
  158. data/test/controller/benchmark_test.rb +3 -3
  159. data/test/controller/caching_test.rb +34 -24
  160. data/test/controller/capture_test.rb +3 -6
  161. data/test/controller/content_type_test.rb +3 -6
  162. data/test/controller/cookie_test.rb +31 -66
  163. data/test/controller/deprecation/deprecated_base_methods_test.rb +9 -11
  164. data/test/controller/dispatcher_test.rb +23 -28
  165. data/test/controller/fake_models.rb +8 -0
  166. data/test/controller/filters_test.rb +6 -2
  167. data/test/controller/flash_test.rb +2 -6
  168. data/test/controller/helper_test.rb +15 -1
  169. data/test/controller/html-scanner/document_test.rb +1 -1
  170. data/test/controller/html-scanner/sanitizer_test.rb +1 -1
  171. data/test/controller/http_basic_authentication_test.rb +88 -0
  172. data/test/controller/http_digest_authentication_test.rb +178 -0
  173. data/test/controller/integration_test.rb +56 -52
  174. data/test/controller/layout_test.rb +46 -44
  175. data/test/controller/middleware_stack_test.rb +90 -0
  176. data/test/controller/mime_responds_test.rb +7 -11
  177. data/test/controller/mime_type_test.rb +9 -0
  178. data/test/controller/polymorphic_routes_test.rb +235 -151
  179. data/test/controller/rack_test.rb +52 -81
  180. data/test/controller/redirect_test.rb +6 -14
  181. data/test/controller/render_test.rb +273 -60
  182. data/test/controller/request/json_params_parsing_test.rb +45 -0
  183. data/test/controller/request/multipart_params_parsing_test.rb +223 -0
  184. data/test/controller/request/query_string_parsing_test.rb +120 -0
  185. data/test/controller/request/url_encoded_params_parsing_test.rb +184 -0
  186. data/test/controller/request/xml_params_parsing_test.rb +88 -0
  187. data/test/controller/request_forgery_protection_test.rb +17 -98
  188. data/test/controller/request_test.rb +45 -530
  189. data/test/controller/rescue_test.rb +45 -22
  190. data/test/controller/resources_test.rb +112 -37
  191. data/test/controller/routing_test.rb +1442 -1384
  192. data/test/controller/selector_test.rb +3 -3
  193. data/test/controller/send_file_test.rb +30 -3
  194. data/test/controller/session/cookie_store_test.rb +169 -240
  195. data/test/controller/session/mem_cache_store_test.rb +94 -148
  196. data/test/controller/session/test_session_test.rb +58 -0
  197. data/test/controller/test_test.rb +32 -13
  198. data/test/controller/url_rewriter_test.rb +54 -4
  199. data/test/controller/verification_test.rb +1 -1
  200. data/test/controller/view_paths_test.rb +15 -15
  201. data/test/controller/webservice_test.rb +178 -147
  202. data/test/fixtures/alternate_helpers/foo_helper.rb +3 -0
  203. data/test/fixtures/layout_tests/alt/layouts/alt.rhtml +0 -0
  204. data/test/fixtures/layouts/default_html.html.erb +1 -0
  205. data/test/fixtures/layouts/xhr.html.erb +2 -0
  206. data/test/fixtures/multipart/empty +10 -0
  207. data/test/fixtures/multipart/hello.txt +1 -0
  208. data/test/fixtures/multipart/none +9 -0
  209. data/test/fixtures/public/500.da.html +1 -0
  210. data/test/fixtures/quiz/questions/_question.html.erb +1 -0
  211. data/test/fixtures/replies.yml +1 -1
  212. data/test/fixtures/test/_one.html.erb +1 -0
  213. data/test/fixtures/test/_two.html.erb +1 -0
  214. data/test/fixtures/test/dont_pick_me +1 -0
  215. data/test/fixtures/test/hello.builder +1 -1
  216. data/test/fixtures/test/hello_world.da.html.erb +1 -0
  217. data/test/fixtures/test/hello_world.erb~ +1 -0
  218. data/test/fixtures/test/hello_world.pt-BR.html.erb +1 -0
  219. data/test/fixtures/test/malformed/malformed.en.html.erb~ +1 -0
  220. data/test/fixtures/test/malformed/malformed.erb~ +1 -0
  221. data/test/fixtures/test/malformed/malformed.html.erb~ +1 -0
  222. data/test/fixtures/test/render_explicit_html_template.js.rjs +1 -0
  223. data/test/fixtures/test/render_implicit_html_template.js.rjs +1 -0
  224. data/test/fixtures/test/render_implicit_html_template_from_xhr_request.da.html.erb +1 -0
  225. data/test/fixtures/test/render_implicit_html_template_from_xhr_request.html.erb +1 -0
  226. data/test/fixtures/test/render_implicit_js_template_without_layout.js.erb +1 -0
  227. data/test/fixtures/test/utf8.html.erb +2 -0
  228. data/test/template/active_record_helper_i18n_test.rb +31 -33
  229. data/test/template/active_record_helper_test.rb +34 -0
  230. data/test/template/asset_tag_helper_test.rb +52 -14
  231. data/test/template/atom_feed_helper_test.rb +3 -5
  232. data/test/template/benchmark_helper_test.rb +50 -24
  233. data/test/template/compiled_templates_test.rb +177 -33
  234. data/test/template/date_helper_i18n_test.rb +88 -81
  235. data/test/template/date_helper_test.rb +427 -43
  236. data/test/template/form_helper_test.rb +243 -44
  237. data/test/template/form_options_helper_test.rb +631 -565
  238. data/test/template/form_tag_helper_test.rb +9 -2
  239. data/test/template/javascript_helper_test.rb +0 -5
  240. data/test/template/number_helper_i18n_test.rb +60 -48
  241. data/test/template/number_helper_test.rb +1 -0
  242. data/test/template/render_test.rb +117 -35
  243. data/test/template/test_test.rb +4 -6
  244. data/test/template/text_helper_test.rb +129 -50
  245. data/test/template/translation_helper_test.rb +23 -19
  246. data/test/template/url_helper_test.rb +35 -2
  247. data/test/view/test_case_test.rb +8 -0
  248. metadata +197 -23
  249. data/lib/action_controller/assertions.rb +0 -69
  250. data/lib/action_controller/caching/sql_cache.rb +0 -18
  251. data/lib/action_controller/cgi_ext/session.rb +0 -53
  252. data/lib/action_controller/components.rb +0 -169
  253. data/lib/action_controller/rack_process.rb +0 -297
  254. data/lib/action_controller/request_profiler.rb +0 -169
  255. data/lib/action_controller/session/active_record_store.rb +0 -340
  256. data/lib/action_controller/session/drb_server.rb +0 -32
  257. data/lib/action_controller/session/drb_store.rb +0 -35
  258. data/test/controller/cgi_test.rb +0 -269
  259. data/test/controller/components_test.rb +0 -156
  260. data/test/controller/http_authentication_test.rb +0 -54
  261. data/test/controller/integration_upload_test.rb +0 -43
  262. data/test/controller/session_fixation_test.rb +0 -89
  263. data/test/controller/session_management_test.rb +0 -178
  264. data/test/fixtures/test/hello_world.js +0 -1
@@ -90,7 +90,7 @@ module ActionController #:nodoc:
90
90
  def verify_action(options) #:nodoc:
91
91
  if prereqs_invalid?(options)
92
92
  flash.update(options[:add_flash]) if options[:add_flash]
93
- response.headers.update(options[:add_headers]) if options[:add_headers]
93
+ response.headers.merge!(options[:add_headers]) if options[:add_headers]
94
94
  apply_remaining_actions(options) unless performed?
95
95
  end
96
96
  end
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2004-2008 David Heinemeier Hansson
2
+ # Copyright (c) 2004-2009 David Heinemeier Hansson
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -1,8 +1,8 @@
1
1
  module ActionPack #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 2
4
- MINOR = 2
5
- TINY = 3
4
+ MINOR = 3
5
+ TINY = 2
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2004-2008 David Heinemeier Hansson
2
+ # Copyright (c) 2004-2009 David Heinemeier Hansson
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -31,23 +31,28 @@ rescue LoadError
31
31
  end
32
32
  end
33
33
 
34
- require 'action_view/template_handlers'
35
- require 'action_view/renderable'
36
- require 'action_view/renderable_partial'
34
+ module ActionView
35
+ def self.load_all!
36
+ [Base, InlineTemplate, TemplateError]
37
+ end
37
38
 
38
- require 'action_view/template'
39
- require 'action_view/inline_template'
40
- require 'action_view/paths'
39
+ autoload :Base, 'action_view/base'
40
+ autoload :Helpers, 'action_view/helpers'
41
+ autoload :InlineTemplate, 'action_view/inline_template'
42
+ autoload :Partials, 'action_view/partials'
43
+ autoload :PathSet, 'action_view/paths'
44
+ autoload :Renderable, 'action_view/renderable'
45
+ autoload :RenderablePartial, 'action_view/renderable_partial'
46
+ autoload :Template, 'action_view/template'
47
+ autoload :ReloadableTemplate, 'action_view/reloadable_template'
48
+ autoload :TemplateError, 'action_view/template_error'
49
+ autoload :TemplateHandler, 'action_view/template_handler'
50
+ autoload :TemplateHandlers, 'action_view/template_handlers'
51
+ autoload :Helpers, 'action_view/helpers'
52
+ end
41
53
 
42
- require 'action_view/base'
43
- require 'action_view/partials'
44
- require 'action_view/template_error'
54
+ class ERB
55
+ autoload :Util, 'action_view/erb/util'
56
+ end
45
57
 
46
58
  I18n.load_path << "#{File.dirname(__FILE__)}/action_view/locale/en.yml"
47
-
48
- require 'action_view/helpers'
49
-
50
- ActionView::Base.class_eval do
51
- include ActionView::Partials
52
- include ActionView::Helpers
53
- end
@@ -3,9 +3,12 @@ module ActionView #:nodoc:
3
3
  end
4
4
 
5
5
  class MissingTemplate < ActionViewError #:nodoc:
6
+ attr_reader :path
7
+
6
8
  def initialize(paths, path, template_format = nil)
9
+ @path = path
7
10
  full_template_path = path.include?('.') ? path : "#{path}.erb"
8
- display_paths = paths.join(':')
11
+ display_paths = paths.compact.join(":")
9
12
  template_type = (path =~ /layouts/i) ? 'layout' : 'template'
10
13
  super("Missing #{template_type} #{full_template_path} in view path #{display_paths}")
11
14
  end
@@ -157,7 +160,7 @@ module ActionView #:nodoc:
157
160
  #
158
161
  # See the ActionView::Helpers::PrototypeHelper::GeneratorMethods documentation for more details.
159
162
  class Base
160
- include ERB::Util
163
+ include Helpers, Partials, ::ERB::Util
161
164
  extend ActiveSupport::Memoizable
162
165
 
163
166
  attr_accessor :base_path, :assigns, :template_extension
@@ -172,25 +175,21 @@ module ActionView #:nodoc:
172
175
  delegate :logger, :to => 'ActionController::Base'
173
176
  end
174
177
 
175
- # Templates that are exempt from layouts
176
- @@exempt_from_layout = Set.new([/\.rjs$/])
177
-
178
- # Don't render layouts for templates with the given extensions.
179
- def self.exempt_from_layout(*extensions)
180
- regexps = extensions.collect do |extension|
181
- extension.is_a?(Regexp) ? extension : /\.#{Regexp.escape(extension.to_s)}$/
182
- end
183
- @@exempt_from_layout.merge(regexps)
184
- end
185
-
178
+ @@debug_rjs = false
179
+ ##
180
+ # :singleton-method:
186
181
  # Specify whether RJS responses should be wrapped in a try/catch block
187
182
  # that alert()s the caught exception (and then re-raises it).
188
- @@debug_rjs = false
189
183
  cattr_accessor :debug_rjs
190
184
 
191
- # A warning will be displayed whenever an action results in a cache miss on your view paths.
192
- @@warn_cache_misses = false
193
- cattr_accessor :warn_cache_misses
185
+ # Specify whether templates should be cached. Otherwise the file we be read everytime it is accessed.
186
+ # Automatically reloading templates are not thread safe and should only be used in development mode.
187
+ @@cache_template_loading = nil
188
+ cattr_accessor :cache_template_loading
189
+
190
+ def self.cache_template_loading?
191
+ ActionController::Base.allow_concurrency || (cache_template_loading.nil? ? !ActiveSupport::Dependencies.load? : cache_template_loading)
192
+ end
194
193
 
195
194
  attr_internal :request
196
195
 
@@ -222,38 +221,43 @@ module ActionView #:nodoc:
222
221
  def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil)#:nodoc:
223
222
  @assigns = assigns_for_first_render
224
223
  @assigns_added = nil
225
- @_render_stack = []
226
224
  @controller = controller
227
225
  @helpers = ProxyModule.new(self)
228
226
  self.view_paths = view_paths
227
+
228
+ @_first_render = nil
229
+ @_current_render = nil
229
230
  end
230
231
 
231
232
  attr_reader :view_paths
232
233
 
233
234
  def view_paths=(paths)
234
235
  @view_paths = self.class.process_view_paths(paths)
236
+ # we might be using ReloadableTemplates, so we need to let them know this a new request
237
+ @view_paths.load!
235
238
  end
236
239
 
237
- # Renders the template present at <tt>template_path</tt> (relative to the view_paths array).
238
- # The hash in <tt>local_assigns</tt> is made available as local variables.
240
+ # Returns the result of a render that's dictated by the options hash. The primary options are:
241
+ #
242
+ # * <tt>:partial</tt> - See ActionView::Partials.
243
+ # * <tt>:update</tt> - Calls update_page with the block given.
244
+ # * <tt>:file</tt> - Renders an explicit template file (this used to be the old default), add :locals to pass in those.
245
+ # * <tt>:inline</tt> - Renders an inline template similar to how it's done in the controller.
246
+ # * <tt>:text</tt> - Renders the text passed in out.
247
+ #
248
+ # If no options hash is passed or :update specified, the default is to render a partial and use the second parameter
249
+ # as the locals hash.
239
250
  def render(options = {}, local_assigns = {}, &block) #:nodoc:
240
251
  local_assigns ||= {}
241
252
 
242
- if options.is_a?(String)
243
- ActiveSupport::Deprecation.warn(
244
- "Calling render with a string will render a partial from Rails 2.3. " +
245
- "Change this call to render(:file => '#{options}', :locals => locals_hash)."
246
- )
247
-
248
- render(:file => options, :locals => local_assigns)
249
- elsif options == :update
250
- update_page(&block)
251
- elsif options.is_a?(Hash)
253
+ case options
254
+ when Hash
252
255
  options = options.reverse_merge(:locals => {})
253
256
  if options[:layout]
254
257
  _render_with_layout(options, local_assigns, &block)
255
258
  elsif options[:file]
256
- _pick_template(options[:file]).render_template(self, options[:locals])
259
+ template = self.view_paths.find_template(options[:file], template_format)
260
+ template.render_template(self, options[:locals])
257
261
  elsif options[:partial]
258
262
  render_partial(options)
259
263
  elsif options[:inline]
@@ -261,6 +265,10 @@ module ActionView #:nodoc:
261
265
  elsif options[:text]
262
266
  options[:text]
263
267
  end
268
+ when :update
269
+ update_page(&block)
270
+ else
271
+ render_partial(:partial => options, :locals => local_assigns)
264
272
  end
265
273
  end
266
274
 
@@ -271,7 +279,7 @@ module ActionView #:nodoc:
271
279
  if defined? @template_format
272
280
  @template_format
273
281
  elsif controller && controller.respond_to?(:request)
274
- @template_format = controller.request.template_format
282
+ @template_format = controller.request.template_format.to_sym
275
283
  else
276
284
  @template_format = :html
277
285
  end
@@ -280,7 +288,19 @@ module ActionView #:nodoc:
280
288
  # Access the current template being rendered.
281
289
  # Returns a ActionView::Template object.
282
290
  def template
283
- @_render_stack.last
291
+ @_current_render
292
+ end
293
+
294
+ def template=(template) #:nodoc:
295
+ @_first_render ||= template
296
+ @_current_render = template
297
+ end
298
+
299
+ def with_template(current_template)
300
+ last_template, self.template = template, current_template
301
+ yield
302
+ ensure
303
+ self.template = last_template
284
304
  end
285
305
 
286
306
  private
@@ -307,52 +327,6 @@ module ActionView #:nodoc:
307
327
  end
308
328
  end
309
329
 
310
- def _pick_template(template_path)
311
- return template_path if template_path.respond_to?(:render)
312
-
313
- path = template_path.sub(/^\//, '')
314
- if m = path.match(/(.*)\.(\w+)$/)
315
- template_file_name, template_file_extension = m[1], m[2]
316
- else
317
- template_file_name = path
318
- end
319
-
320
- # OPTIMIZE: Checks to lookup template in view path
321
- if template = self.view_paths["#{template_file_name}.#{template_format}"]
322
- template
323
- elsif template_file_extension && template = self.view_paths["#{template_file_name}.#{template_file_extension}"]
324
- template
325
- elsif template = self.view_paths[template_file_name]
326
- template
327
- elsif (first_render = @_render_stack.first) && first_render.respond_to?(:format_and_extension) &&
328
- (template = self.view_paths["#{template_file_name}.#{first_render.format_and_extension}"])
329
- template
330
- elsif template_format == :js && template = self.view_paths["#{template_file_name}.html"]
331
- @template_format = :html
332
- template
333
- else
334
- template = Template.new(template_path, view_paths)
335
-
336
- if self.class.warn_cache_misses && logger
337
- logger.debug "[PERFORMANCE] Rendering a template that was " +
338
- "not found in view path. Templates outside the view path are " +
339
- "not cached and result in expensive disk operations. Move this " +
340
- "file into #{view_paths.join(':')} or add the folder to your " +
341
- "view path list"
342
- end
343
-
344
- template
345
- end
346
- end
347
- memoize :_pick_template
348
-
349
- def _exempt_from_layout?(template_path) #:nodoc:
350
- template = _pick_template(template_path).to_s
351
- @@exempt_from_layout.any? { |ext| template =~ ext }
352
- rescue ActionView::MissingTemplate
353
- return false
354
- end
355
-
356
330
  def _render_with_layout(options, local_assigns, &block) #:nodoc:
357
331
  partial_layout = options.delete(:layout)
358
332
 
@@ -0,0 +1,38 @@
1
+ require 'erb'
2
+
3
+ class ERB
4
+ module Util
5
+ HTML_ESCAPE = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;' }
6
+ JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003E', '<' => '\u003C' }
7
+
8
+ # A utility method for escaping HTML tag characters.
9
+ # This method is also aliased as <tt>h</tt>.
10
+ #
11
+ # In your ERb templates, use this method to escape any unsafe content. For example:
12
+ # <%=h @person.name %>
13
+ #
14
+ # ==== Example:
15
+ # puts html_escape("is a > 0 & a < 10?")
16
+ # # => is a &gt; 0 &amp; a &lt; 10?
17
+ def html_escape(s)
18
+ s.to_s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }
19
+ end
20
+
21
+ # A utility method for escaping HTML entities in JSON strings.
22
+ # This method is also aliased as <tt>j</tt>.
23
+ #
24
+ # In your ERb templates, use this method to escape any HTML entities:
25
+ # <%=j @person.to_json %>
26
+ #
27
+ # ==== Example:
28
+ # puts json_escape("is a > 0 & a < 10?")
29
+ # # => is a \u003E 0 \u0026 a \u003C 10?
30
+ def json_escape(s)
31
+ s.to_s.gsub(/[&"><]/) { |special| JSON_ESCAPE[special] }
32
+ end
33
+
34
+ alias j json_escape
35
+ module_function :j
36
+ module_function :json_escape
37
+ end
38
+ end
@@ -1,10 +1,28 @@
1
- Dir.entries(File.expand_path("#{File.dirname(__FILE__)}/helpers")).sort.each do |file|
2
- next unless file =~ /^([a-z][a-z_]*_helper).rb$/
3
- require "action_view/helpers/#{$1}"
4
- end
5
-
6
1
  module ActionView #:nodoc:
7
2
  module Helpers #:nodoc:
3
+ autoload :ActiveRecordHelper, 'action_view/helpers/active_record_helper'
4
+ autoload :AssetTagHelper, 'action_view/helpers/asset_tag_helper'
5
+ autoload :AtomFeedHelper, 'action_view/helpers/atom_feed_helper'
6
+ autoload :BenchmarkHelper, 'action_view/helpers/benchmark_helper'
7
+ autoload :CacheHelper, 'action_view/helpers/cache_helper'
8
+ autoload :CaptureHelper, 'action_view/helpers/capture_helper'
9
+ autoload :DateHelper, 'action_view/helpers/date_helper'
10
+ autoload :DebugHelper, 'action_view/helpers/debug_helper'
11
+ autoload :FormHelper, 'action_view/helpers/form_helper'
12
+ autoload :FormOptionsHelper, 'action_view/helpers/form_options_helper'
13
+ autoload :FormTagHelper, 'action_view/helpers/form_tag_helper'
14
+ autoload :JavascriptHelper, 'action_view/helpers/javascript_helper'
15
+ autoload :NumberHelper, 'action_view/helpers/number_helper'
16
+ autoload :PrototypeHelper, 'action_view/helpers/prototype_helper'
17
+ autoload :RecordIdentificationHelper, 'action_view/helpers/record_identification_helper'
18
+ autoload :RecordTagHelper, 'action_view/helpers/record_tag_helper'
19
+ autoload :SanitizeHelper, 'action_view/helpers/sanitize_helper'
20
+ autoload :ScriptaculousHelper, 'action_view/helpers/scriptaculous_helper'
21
+ autoload :TagHelper, 'action_view/helpers/tag_helper'
22
+ autoload :TextHelper, 'action_view/helpers/text_helper'
23
+ autoload :TranslationHelper, 'action_view/helpers/translation_helper'
24
+ autoload :UrlHelper, 'action_view/helpers/url_helper'
25
+
8
26
  def self.included(base)
9
27
  base.extend(ClassMethods)
10
28
  end
@@ -24,6 +42,7 @@ module ActionView #:nodoc:
24
42
  include FormHelper
25
43
  include FormOptionsHelper
26
44
  include FormTagHelper
45
+ include JavaScriptHelper
27
46
  include NumberHelper
28
47
  include PrototypeHelper
29
48
  include RecordIdentificationHelper
@@ -121,7 +121,7 @@ module ActionView
121
121
  if (obj = (object.respond_to?(:errors) ? object : instance_variable_get("@#{object}"))) &&
122
122
  (errors = obj.errors.on(method))
123
123
  content_tag("div",
124
- "#{options[:prepend_text]}#{errors.is_a?(Array) ? errors.first : errors}#{options[:append_text]}",
124
+ "#{options[:prepend_text]}#{ERB::Util.html_escape(errors.is_a?(Array) ? errors.first : errors)}#{options[:append_text]}",
125
125
  :class => options[:css_class]
126
126
  )
127
127
  else
@@ -198,7 +198,7 @@ module ActionView
198
198
  locale.t :header, :count => count, :model => object_name
199
199
  end
200
200
  message = options.include?(:message) ? options[:message] : locale.t(:body)
201
- error_messages = objects.sum {|object| object.errors.full_messages.map {|msg| content_tag(:li, msg) } }.join
201
+ error_messages = objects.sum {|object| object.errors.full_messages.map {|msg| content_tag(:li, ERB::Util.html_escape(msg)) } }.join
202
202
 
203
203
  contents = ''
204
204
  contents << content_tag(options[:header_tag] || :h2, header_message) unless header_message.blank?
@@ -6,54 +6,70 @@ module ActionView
6
6
  module Helpers #:nodoc:
7
7
  # This module provides methods for generating HTML that links views to assets such
8
8
  # as images, javascripts, stylesheets, and feeds. These methods do not verify
9
- # the assets exist before linking to them.
9
+ # the assets exist before linking to them:
10
+ #
11
+ # image_tag("rails.png")
12
+ # # => <img alt="Rails src="/images/rails.png?1230601161" />
13
+ # stylesheet_link_tag("application")
14
+ # # => <link href="/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" type="text/css" />
10
15
  #
11
16
  # === Using asset hosts
17
+ #
12
18
  # By default, Rails links to these assets on the current host in the public
13
- # folder, but you can direct Rails to link to assets from a dedicated assets server by
14
- # setting ActionController::Base.asset_host in your <tt>config/environment.rb</tt>. For example,
15
- # let's say your asset host is <tt>assets.example.com</tt>.
19
+ # folder, but you can direct Rails to link to assets from a dedicated asset
20
+ # server by setting ActionController::Base.asset_host in the application
21
+ # configuration, typically in <tt>config/environments/production.rb</tt>.
22
+ # For example, you'd define <tt>assets.example.com</tt> to be your asset
23
+ # host this way:
16
24
  #
17
25
  # ActionController::Base.asset_host = "assets.example.com"
26
+ #
27
+ # Helpers take that into account:
28
+ #
18
29
  # image_tag("rails.png")
19
- # => <img src="http://assets.example.com/images/rails.png" alt="Rails" />
30
+ # # => <img alt="Rails" src="http://assets.example.com/images/rails.png?1230601161" />
20
31
  # stylesheet_link_tag("application")
21
- # => <link href="http://assets.example.com/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />
32
+ # # => <link href="http://assets.example.com/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" type="text/css" />
22
33
  #
23
- # This is useful since browsers typically open at most two connections to a single host,
24
- # which means your assets often wait in single file for their turn to load. You can
25
- # alleviate this by using a <tt>%d</tt> wildcard in <tt>asset_host</tt> (for example, "assets%d.example.com")
26
- # to automatically distribute asset requests among four hosts (e.g., "assets0.example.com" through "assets3.example.com")
27
- # so browsers will open eight connections rather than two.
34
+ # Browsers typically open at most two simultaneous connections to a single
35
+ # host, which means your assets often have to wait for other assets to finish
36
+ # downloading. You can alleviate this by using a <tt>%d</tt> wildcard in the
37
+ # +asset_host+. For example, "assets%d.example.com". If that wildcard is
38
+ # present Rails distributes asset requests among the corresponding four hosts
39
+ # "assets0.example.com", ..., "assets3.example.com". With this trick browsers
40
+ # will open eight simultaneous connections rather than two.
28
41
  #
29
42
  # image_tag("rails.png")
30
- # => <img src="http://assets0.example.com/images/rails.png" alt="Rails" />
43
+ # # => <img alt="Rails" src="http://assets0.example.com/images/rails.png?1230601161" />
31
44
  # stylesheet_link_tag("application")
32
- # => <link href="http://assets3.example.com/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />
45
+ # # => <link href="http://assets2.example.com/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" type="text/css" />
33
46
  #
34
- # To do this, you can either setup 4 actual hosts, or you can use wildcard DNS to CNAME
35
- # the wildcard to a single asset host. You can read more about setting up your DNS CNAME records from
36
- # your ISP.
47
+ # To do this, you can either setup four actual hosts, or you can use wildcard
48
+ # DNS to CNAME the wildcard to a single asset host. You can read more about
49
+ # setting up your DNS CNAME records from your ISP.
37
50
  #
38
51
  # Note: This is purely a browser performance optimization and is not meant
39
52
  # for server load balancing. See http://www.die.net/musings/page_load_time/
40
53
  # for background.
41
54
  #
42
- # Alternatively, you can exert more control over the asset host by setting <tt>asset_host</tt> to a proc
43
- # that takes a single source argument. This is useful if you are unable to setup 4 actual hosts or have
44
- # fewer/more than 4 hosts. The example proc below generates http://assets1.example.com and
45
- # http://assets2.example.com randomly.
55
+ # Alternatively, you can exert more control over the asset host by setting
56
+ # +asset_host+ to a proc like this:
46
57
  #
47
- # ActionController::Base.asset_host = Proc.new { |source| "http://assets#{rand(2) + 1}.example.com" }
58
+ # ActionController::Base.asset_host = Proc.new { |source|
59
+ # "http://assets#{rand(2) + 1}.example.com"
60
+ # }
48
61
  # image_tag("rails.png")
49
- # => <img src="http://assets2.example.com/images/rails.png" alt="Rails" />
62
+ # # => <img alt="Rails" src="http://assets0.example.com/images/rails.png?1230601161" />
50
63
  # stylesheet_link_tag("application")
51
- # => <link href="http://assets1.example.com/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />
64
+ # # => <link href="http://assets1.example.com/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" type="text/css" />
65
+ #
66
+ # The example above generates "http://assets1.example.com" and
67
+ # "http://assets2.example.com" randomly. This option is useful for example if
68
+ # you need fewer/more than four hosts, custom host names, etc.
52
69
  #
53
- # The proc takes a <tt>source</tt> parameter (which is the path of the source asset) and an optional
54
- # <tt>request</tt> parameter (which is an entire instance of an <tt>ActionController::AbstractRequest</tt>
55
- # subclass). This can be used to generate a particular asset host depending on the asset path and the particular
56
- # request.
70
+ # As you see the proc takes a +source+ parameter. That's a string with the
71
+ # absolute path of the asset with any extensions and timestamps in place,
72
+ # for example "/images/rails.png?1230601161".
57
73
  #
58
74
  # ActionController::Base.asset_host = Proc.new { |source|
59
75
  # if source.starts_with?('/images')
@@ -63,14 +79,16 @@ module ActionView
63
79
  # end
64
80
  # }
65
81
  # image_tag("rails.png")
66
- # => <img src="http://images.example.com/images/rails.png" alt="Rails" />
82
+ # # => <img alt="Rails" src="http://images.example.com/images/rails.png?1230601161" />
67
83
  # stylesheet_link_tag("application")
68
- # => <link href="http://assets.example.com/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />
84
+ # # => <link href="http://assets.example.com/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" type="text/css" />
69
85
  #
70
- # The optional <tt>request</tt> parameter to the proc is useful in particular for serving assets from an
71
- # SSL-protected page. The example proc below disables asset hosting for HTTPS connections, while still sending
72
- # assets for plain HTTP requests from asset hosts. This is useful for avoiding mixed media warnings when serving
73
- # non-HTTP assets from HTTPS web pages when you don't have an SSL certificate for each of the asset hosts.
86
+ # Alternatively you may ask for a second parameter +request+. That one is
87
+ # particularly useful for serving assets from an SSL-protected page. The
88
+ # example proc below disables asset hosting for HTTPS connections, while
89
+ # still sending assets for plain HTTP requests from asset hosts. If you don't
90
+ # have SSL certificates for each of the asset hosts this technique allows you
91
+ # to avoid warnings in the client about mixed media.
74
92
  #
75
93
  # ActionController::Base.asset_host = Proc.new { |source, request|
76
94
  # if request.ssl?
@@ -80,26 +98,38 @@ module ActionView
80
98
  # end
81
99
  # }
82
100
  #
101
+ # You can also implement a custom asset host object that responds to +call+
102
+ # and takes either one or two parameters just like the proc.
103
+ #
104
+ # config.action_controller.asset_host = AssetHostingWithMinimumSsl.new(
105
+ # "http://asset%d.example.com", "https://asset1.example.com"
106
+ # )
107
+ #
83
108
  # === Using asset timestamps
84
109
  #
85
- # By default, Rails will append all asset paths with that asset's timestamp. This allows you to set a cache-expiration date for the
86
- # asset far into the future, but still be able to instantly invalidate it by simply updating the file (and hence updating the timestamp,
87
- # which then updates the URL as the timestamp is part of that, which in turn busts the cache).
110
+ # By default, Rails appends asset's timestamps to all asset paths. This allows
111
+ # you to set a cache-expiration date for the asset far into the future, but
112
+ # still be able to instantly invalidate it by simply updating the file (and
113
+ # hence updating the timestamp, which then updates the URL as the timestamp
114
+ # is part of that, which in turn busts the cache).
88
115
  #
89
- # It's the responsibility of the web server you use to set the far-future expiration date on cache assets that you need to take
90
- # advantage of this feature. Here's an example for Apache:
116
+ # It's the responsibility of the web server you use to set the far-future
117
+ # expiration date on cache assets that you need to take advantage of this
118
+ # feature. Here's an example for Apache:
91
119
  #
92
- # # Asset Expiration
93
- # ExpiresActive On
94
- # <FilesMatch "\.(ico|gif|jpe?g|png|js|css)$">
95
- # ExpiresDefault "access plus 1 year"
96
- # </FilesMatch>
120
+ # # Asset Expiration
121
+ # ExpiresActive On
122
+ # <FilesMatch "\.(ico|gif|jpe?g|png|js|css)$">
123
+ # ExpiresDefault "access plus 1 year"
124
+ # </FilesMatch>
97
125
  #
98
- # Also note that in order for this to work, all your application servers must return the same timestamps. This means that they must
99
- # have their clocks synchronized. If one of them drift out of sync, you'll see different timestamps at random and the cache won't
100
- # work. Which means that the browser will request the same assets over and over again even thought they didn't change. You can use
101
- # something like Live HTTP Headers for Firefox to verify that the cache is indeed working (and that the assets are not being
102
- # requested over and over).
126
+ # Also note that in order for this to work, all your application servers must
127
+ # return the same timestamps. This means that they must have their clocks
128
+ # synchronized. If one of them drifts out of sync, you'll see different
129
+ # timestamps at random and the cache won't work. In that case the browser
130
+ # will request the same assets over and over again even thought they didn't
131
+ # change. You can use something like Live HTTP Headers for Firefox to verify
132
+ # that the cache is indeed working.
103
133
  module AssetTagHelper
104
134
  ASSETS_DIR = defined?(Rails.public_path) ? Rails.public_path : "public"
105
135
  JAVASCRIPTS_DIR = "#{ASSETS_DIR}/javascripts"
@@ -111,7 +141,7 @@ module ActionView
111
141
  # <tt>:atom</tt>. Control the link options in url_for format using the
112
142
  # +url_options+. You can modify the LINK tag itself in +tag_options+.
113
143
  #
114
- # ==== Options:
144
+ # ==== Options
115
145
  # * <tt>:rel</tt> - Specify the relation of this link, defaults to "alternate"
116
146
  # * <tt>:type</tt> - Override the auto-generated mime type
117
147
  # * <tt>:title</tt> - Specify the title of the link, defaults to the +type+
@@ -486,7 +516,8 @@ module ActionView
486
516
  def compute_public_path(source, dir, ext = nil, include_host = true)
487
517
  has_request = @controller.respond_to?(:request)
488
518
 
489
- if ext && (File.extname(source).blank? || File.exist?(File.join(ASSETS_DIR, dir, "#{source}.#{ext}")))
519
+ source_ext = File.extname(source)[1..-1]
520
+ if ext && (source_ext.blank? || (ext != source_ext && File.exist?(File.join(ASSETS_DIR, dir, "#{source}.#{ext}"))))
490
521
  source += ".#{ext}"
491
522
  end
492
523