actionpack 3.2.19 → 4.2.11.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 (244) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +412 -503
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +11 -294
  5. data/lib/abstract_controller/asset_paths.rb +2 -2
  6. data/lib/abstract_controller/base.rb +52 -18
  7. data/lib/abstract_controller/callbacks.rb +87 -89
  8. data/lib/abstract_controller/collector.rb +17 -3
  9. data/lib/abstract_controller/helpers.rb +41 -14
  10. data/lib/abstract_controller/logger.rb +1 -2
  11. data/lib/abstract_controller/railties/routes_helpers.rb +3 -3
  12. data/lib/abstract_controller/rendering.rb +65 -118
  13. data/lib/abstract_controller/translation.rb +16 -1
  14. data/lib/abstract_controller/url_for.rb +7 -7
  15. data/lib/abstract_controller.rb +2 -10
  16. data/lib/action_controller/base.rb +61 -28
  17. data/lib/action_controller/caching/fragments.rb +30 -54
  18. data/lib/action_controller/caching.rb +38 -35
  19. data/lib/action_controller/log_subscriber.rb +35 -18
  20. data/lib/action_controller/metal/conditional_get.rb +103 -34
  21. data/lib/action_controller/metal/data_streaming.rb +20 -26
  22. data/lib/action_controller/metal/etag_with_template_digest.rb +50 -0
  23. data/lib/action_controller/metal/exceptions.rb +19 -6
  24. data/lib/action_controller/metal/flash.rb +41 -9
  25. data/lib/action_controller/metal/force_ssl.rb +70 -12
  26. data/lib/action_controller/metal/head.rb +30 -7
  27. data/lib/action_controller/metal/helpers.rb +11 -11
  28. data/lib/action_controller/metal/hide_actions.rb +0 -1
  29. data/lib/action_controller/metal/http_authentication.rb +140 -94
  30. data/lib/action_controller/metal/implicit_render.rb +1 -1
  31. data/lib/action_controller/metal/instrumentation.rb +11 -7
  32. data/lib/action_controller/metal/live.rb +328 -0
  33. data/lib/action_controller/metal/mime_responds.rb +161 -152
  34. data/lib/action_controller/metal/params_wrapper.rb +126 -81
  35. data/lib/action_controller/metal/rack_delegation.rb +10 -4
  36. data/lib/action_controller/metal/redirecting.rb +44 -41
  37. data/lib/action_controller/metal/renderers.rb +48 -19
  38. data/lib/action_controller/metal/rendering.rb +46 -11
  39. data/lib/action_controller/metal/request_forgery_protection.rb +250 -29
  40. data/lib/action_controller/metal/streaming.rb +30 -38
  41. data/lib/action_controller/metal/strong_parameters.rb +669 -0
  42. data/lib/action_controller/metal/testing.rb +12 -18
  43. data/lib/action_controller/metal/url_for.rb +31 -29
  44. data/lib/action_controller/metal.rb +31 -40
  45. data/lib/action_controller/model_naming.rb +12 -0
  46. data/lib/action_controller/railtie.rb +38 -18
  47. data/lib/action_controller/railties/helpers.rb +22 -0
  48. data/lib/action_controller/test_case.rb +359 -173
  49. data/lib/action_controller.rb +9 -16
  50. data/lib/action_dispatch/http/cache.rb +64 -11
  51. data/lib/action_dispatch/http/filter_parameters.rb +20 -10
  52. data/lib/action_dispatch/http/filter_redirect.rb +38 -0
  53. data/lib/action_dispatch/http/headers.rb +85 -17
  54. data/lib/action_dispatch/http/mime_negotiation.rb +55 -5
  55. data/lib/action_dispatch/http/mime_type.rb +167 -114
  56. data/lib/action_dispatch/http/mime_types.rb +2 -1
  57. data/lib/action_dispatch/http/parameter_filter.rb +44 -46
  58. data/lib/action_dispatch/http/parameters.rb +30 -46
  59. data/lib/action_dispatch/http/rack_cache.rb +2 -3
  60. data/lib/action_dispatch/http/request.rb +108 -45
  61. data/lib/action_dispatch/http/response.rb +247 -48
  62. data/lib/action_dispatch/http/upload.rb +60 -29
  63. data/lib/action_dispatch/http/url.rb +135 -45
  64. data/lib/action_dispatch/journey/backwards.rb +5 -0
  65. data/lib/action_dispatch/journey/formatter.rb +166 -0
  66. data/lib/action_dispatch/journey/gtg/builder.rb +162 -0
  67. data/lib/action_dispatch/journey/gtg/simulator.rb +47 -0
  68. data/lib/action_dispatch/journey/gtg/transition_table.rb +157 -0
  69. data/lib/action_dispatch/journey/nfa/builder.rb +76 -0
  70. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  71. data/lib/action_dispatch/journey/nfa/simulator.rb +47 -0
  72. data/lib/action_dispatch/journey/nfa/transition_table.rb +163 -0
  73. data/lib/action_dispatch/journey/nodes/node.rb +128 -0
  74. data/lib/action_dispatch/journey/parser.rb +198 -0
  75. data/lib/action_dispatch/journey/parser.y +49 -0
  76. data/lib/action_dispatch/journey/parser_extras.rb +23 -0
  77. data/lib/action_dispatch/journey/path/pattern.rb +193 -0
  78. data/lib/action_dispatch/journey/route.rb +125 -0
  79. data/lib/action_dispatch/journey/router/strexp.rb +27 -0
  80. data/lib/action_dispatch/journey/router/utils.rb +93 -0
  81. data/lib/action_dispatch/journey/router.rb +144 -0
  82. data/lib/action_dispatch/journey/routes.rb +80 -0
  83. data/lib/action_dispatch/journey/scanner.rb +61 -0
  84. data/lib/action_dispatch/journey/visitors.rb +221 -0
  85. data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
  86. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  87. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  88. data/lib/action_dispatch/journey.rb +5 -0
  89. data/lib/action_dispatch/middleware/callbacks.rb +16 -11
  90. data/lib/action_dispatch/middleware/cookies.rb +346 -125
  91. data/lib/action_dispatch/middleware/debug_exceptions.rb +52 -24
  92. data/lib/action_dispatch/middleware/exception_wrapper.rb +75 -9
  93. data/lib/action_dispatch/middleware/flash.rb +85 -72
  94. data/lib/action_dispatch/middleware/params_parser.rb +16 -31
  95. data/lib/action_dispatch/middleware/public_exceptions.rb +39 -14
  96. data/lib/action_dispatch/middleware/reloader.rb +16 -7
  97. data/lib/action_dispatch/middleware/remote_ip.rb +132 -40
  98. data/lib/action_dispatch/middleware/request_id.rb +3 -7
  99. data/lib/action_dispatch/middleware/session/abstract_store.rb +22 -20
  100. data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
  101. data/lib/action_dispatch/middleware/session/cookie_store.rb +84 -29
  102. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -3
  103. data/lib/action_dispatch/middleware/show_exceptions.rb +15 -44
  104. data/lib/action_dispatch/middleware/ssl.rb +72 -0
  105. data/lib/action_dispatch/middleware/stack.rb +6 -1
  106. data/lib/action_dispatch/middleware/static.rb +80 -23
  107. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +34 -0
  108. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  109. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +27 -0
  110. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
  111. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  112. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +16 -0
  113. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  114. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +133 -5
  115. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  116. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  117. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  119. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  121. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
  122. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  123. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  124. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +200 -0
  125. data/lib/action_dispatch/railtie.rb +19 -6
  126. data/lib/action_dispatch/request/session.rb +193 -0
  127. data/lib/action_dispatch/request/utils.rb +35 -0
  128. data/lib/action_dispatch/routing/endpoint.rb +10 -0
  129. data/lib/action_dispatch/routing/inspector.rb +234 -0
  130. data/lib/action_dispatch/routing/mapper.rb +897 -436
  131. data/lib/action_dispatch/routing/polymorphic_routes.rb +213 -92
  132. data/lib/action_dispatch/routing/redirection.rb +97 -37
  133. data/lib/action_dispatch/routing/route_set.rb +432 -239
  134. data/lib/action_dispatch/routing/routes_proxy.rb +7 -4
  135. data/lib/action_dispatch/routing/url_for.rb +63 -34
  136. data/lib/action_dispatch/routing.rb +57 -89
  137. data/lib/action_dispatch/testing/assertions/dom.rb +2 -36
  138. data/lib/action_dispatch/testing/assertions/response.rb +24 -38
  139. data/lib/action_dispatch/testing/assertions/routing.rb +55 -54
  140. data/lib/action_dispatch/testing/assertions/selector.rb +2 -434
  141. data/lib/action_dispatch/testing/assertions/tag.rb +2 -137
  142. data/lib/action_dispatch/testing/assertions.rb +11 -7
  143. data/lib/action_dispatch/testing/integration.rb +88 -72
  144. data/lib/action_dispatch/testing/test_process.rb +9 -6
  145. data/lib/action_dispatch/testing/test_request.rb +13 -9
  146. data/lib/action_dispatch/testing/test_response.rb +1 -5
  147. data/lib/action_dispatch.rb +24 -21
  148. data/lib/action_pack/gem_version.rb +15 -0
  149. data/lib/action_pack/version.rb +5 -7
  150. data/lib/action_pack.rb +1 -1
  151. metadata +181 -292
  152. data/lib/abstract_controller/layouts.rb +0 -423
  153. data/lib/abstract_controller/view_paths.rb +0 -96
  154. data/lib/action_controller/caching/actions.rb +0 -185
  155. data/lib/action_controller/caching/pages.rb +0 -187
  156. data/lib/action_controller/caching/sweeping.rb +0 -97
  157. data/lib/action_controller/deprecated/integration_test.rb +0 -2
  158. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  159. data/lib/action_controller/deprecated.rb +0 -3
  160. data/lib/action_controller/metal/compatibility.rb +0 -65
  161. data/lib/action_controller/metal/responder.rb +0 -286
  162. data/lib/action_controller/metal/session_management.rb +0 -14
  163. data/lib/action_controller/railties/paths.rb +0 -25
  164. data/lib/action_controller/record_identifier.rb +0 -85
  165. data/lib/action_controller/vendor/html-scanner/html/document.rb +0 -68
  166. data/lib/action_controller/vendor/html-scanner/html/node.rb +0 -532
  167. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +0 -177
  168. data/lib/action_controller/vendor/html-scanner/html/selector.rb +0 -830
  169. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +0 -107
  170. data/lib/action_controller/vendor/html-scanner/html/version.rb +0 -11
  171. data/lib/action_controller/vendor/html-scanner.rb +0 -20
  172. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  173. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  174. data/lib/action_dispatch/middleware/head.rb +0 -18
  175. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  176. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +0 -31
  177. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +0 -26
  178. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +0 -10
  179. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +0 -2
  180. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +0 -15
  181. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +0 -17
  182. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +0 -2
  183. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  184. data/lib/action_view/asset_paths.rb +0 -142
  185. data/lib/action_view/base.rb +0 -220
  186. data/lib/action_view/buffers.rb +0 -43
  187. data/lib/action_view/context.rb +0 -36
  188. data/lib/action_view/flows.rb +0 -79
  189. data/lib/action_view/helpers/active_model_helper.rb +0 -50
  190. data/lib/action_view/helpers/asset_paths.rb +0 -7
  191. data/lib/action_view/helpers/asset_tag_helper.rb +0 -457
  192. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  193. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  194. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  195. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  196. data/lib/action_view/helpers/atom_feed_helper.rb +0 -200
  197. data/lib/action_view/helpers/cache_helper.rb +0 -64
  198. data/lib/action_view/helpers/capture_helper.rb +0 -203
  199. data/lib/action_view/helpers/controller_helper.rb +0 -25
  200. data/lib/action_view/helpers/csrf_helper.rb +0 -32
  201. data/lib/action_view/helpers/date_helper.rb +0 -1062
  202. data/lib/action_view/helpers/debug_helper.rb +0 -40
  203. data/lib/action_view/helpers/form_helper.rb +0 -1486
  204. data/lib/action_view/helpers/form_options_helper.rb +0 -658
  205. data/lib/action_view/helpers/form_tag_helper.rb +0 -685
  206. data/lib/action_view/helpers/javascript_helper.rb +0 -110
  207. data/lib/action_view/helpers/number_helper.rb +0 -622
  208. data/lib/action_view/helpers/output_safety_helper.rb +0 -38
  209. data/lib/action_view/helpers/record_tag_helper.rb +0 -111
  210. data/lib/action_view/helpers/rendering_helper.rb +0 -90
  211. data/lib/action_view/helpers/sanitize_helper.rb +0 -259
  212. data/lib/action_view/helpers/tag_helper.rb +0 -160
  213. data/lib/action_view/helpers/text_helper.rb +0 -426
  214. data/lib/action_view/helpers/translation_helper.rb +0 -91
  215. data/lib/action_view/helpers/url_helper.rb +0 -693
  216. data/lib/action_view/helpers.rb +0 -60
  217. data/lib/action_view/locale/en.yml +0 -160
  218. data/lib/action_view/log_subscriber.rb +0 -28
  219. data/lib/action_view/lookup_context.rb +0 -254
  220. data/lib/action_view/path_set.rb +0 -89
  221. data/lib/action_view/railtie.rb +0 -55
  222. data/lib/action_view/renderer/abstract_renderer.rb +0 -41
  223. data/lib/action_view/renderer/partial_renderer.rb +0 -415
  224. data/lib/action_view/renderer/renderer.rb +0 -54
  225. data/lib/action_view/renderer/streaming_template_renderer.rb +0 -106
  226. data/lib/action_view/renderer/template_renderer.rb +0 -94
  227. data/lib/action_view/template/error.rb +0 -128
  228. data/lib/action_view/template/handlers/builder.rb +0 -26
  229. data/lib/action_view/template/handlers/erb.rb +0 -125
  230. data/lib/action_view/template/handlers.rb +0 -50
  231. data/lib/action_view/template/resolver.rb +0 -272
  232. data/lib/action_view/template/text.rb +0 -30
  233. data/lib/action_view/template.rb +0 -337
  234. data/lib/action_view/test_case.rb +0 -245
  235. data/lib/action_view/testing/resolvers.rb +0 -50
  236. data/lib/action_view.rb +0 -84
  237. data/lib/sprockets/assets.rake +0 -99
  238. data/lib/sprockets/bootstrap.rb +0 -37
  239. data/lib/sprockets/compressors.rb +0 -83
  240. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  241. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  242. data/lib/sprockets/helpers.rb +0 -6
  243. data/lib/sprockets/railtie.rb +0 -62
  244. data/lib/sprockets/static_compiler.rb +0 -56
@@ -1,3 +1,5 @@
1
+ require 'action_controller/model_naming'
2
+
1
3
  module ActionDispatch
2
4
  module Routing
3
5
  # Polymorphic URL helpers are methods for smart resolution to a named route call when
@@ -32,7 +34,7 @@ module ActionDispatch
32
34
  # == Prefixed polymorphic helpers
33
35
  #
34
36
  # In addition to <tt>polymorphic_url</tt> and <tt>polymorphic_path</tt> methods, a
35
- # number of prefixed helpers are available as a shorthand to <tt>:action => "..."</tt>
37
+ # number of prefixed helpers are available as a shorthand to <tt>action: "..."</tt>
36
38
  # in options. Those are:
37
39
  #
38
40
  # * <tt>edit_polymorphic_url</tt>, <tt>edit_polymorphic_path</tt>
@@ -41,20 +43,20 @@ module ActionDispatch
41
43
  # Example usage:
42
44
  #
43
45
  # edit_polymorphic_path(@post) # => "/posts/1/edit"
44
- # polymorphic_path(@post, :format => :pdf) # => "/posts/1.pdf"
45
- #
46
- # == Using with mounted engines
46
+ # polymorphic_path(@post, format: :pdf) # => "/posts/1.pdf"
47
47
  #
48
- # If you use mounted engine, there is a possibility that you will need to use
49
- # polymorphic_url pointing at engine's routes. To do that, just pass proxy used
50
- # to reach engine's routes as a first argument:
48
+ # == Usage with mounted engines
51
49
  #
52
- # For example:
50
+ # If you are using a mounted engine and you need to use a polymorphic_url
51
+ # pointing at the engine's routes, pass in the engine's route proxy as the first
52
+ # argument to the method. For example:
53
53
  #
54
- # polymorphic_url([blog, @post]) # it will call blog.post_path(@post)
55
- # form_for([blog, @post]) # => "/blog/posts/1
54
+ # polymorphic_url([blog, @post]) # calls blog.post_path(@post)
55
+ # form_for([blog, @post]) # => "/blog/posts/1"
56
56
  #
57
57
  module PolymorphicRoutes
58
+ include ActionController::ModelNaming
59
+
58
60
  # Constructs a call to a named RESTful route for the given record and returns the
59
61
  # resulting URL string. For example:
60
62
  #
@@ -72,7 +74,18 @@ module ActionDispatch
72
74
  # * <tt>:routing_type</tt> - Allowed values are <tt>:path</tt> or <tt>:url</tt>.
73
75
  # Default is <tt>:url</tt>.
74
76
  #
75
- # ==== Examples
77
+ # Also includes all the options from <tt>url_for</tt>. These include such
78
+ # things as <tt>:anchor</tt> or <tt>:trailing_slash</tt>. Example usage
79
+ # is given below:
80
+ #
81
+ # polymorphic_url([blog, post], anchor: 'my_anchor')
82
+ # # => "http://example.com/blogs/1/posts/1#my_anchor"
83
+ # polymorphic_url([blog, post], anchor: 'my_anchor', script_name: "/my_app")
84
+ # # => "http://example.com/my_app/blogs/1/posts/1#my_anchor"
85
+ #
86
+ # For all of these options, see the documentation for <tt>url_for</tt>.
87
+ #
88
+ # ==== Functionality
76
89
  #
77
90
  # # an Article record
78
91
  # polymorphic_url(record) # same as article_url(record)
@@ -88,122 +101,230 @@ module ActionDispatch
88
101
  # polymorphic_url(Comment) # same as comments_url()
89
102
  #
90
103
  def polymorphic_url(record_or_hash_or_array, options = {})
91
- if record_or_hash_or_array.kind_of?(Array)
92
- record_or_hash_or_array = record_or_hash_or_array.compact
93
- if record_or_hash_or_array.first.is_a?(ActionDispatch::Routing::RoutesProxy)
94
- proxy = record_or_hash_or_array.shift
95
- end
96
- record_or_hash_or_array = record_or_hash_or_array[0] if record_or_hash_or_array.size == 1
104
+ if Hash === record_or_hash_or_array
105
+ options = record_or_hash_or_array.merge(options)
106
+ record = options.delete :id
107
+ return polymorphic_url record, options
97
108
  end
98
109
 
99
- record = extract_record(record_or_hash_or_array)
100
- record = convert_to_model(record)
101
-
102
- args = Array === record_or_hash_or_array ?
103
- record_or_hash_or_array.dup :
104
- [ record_or_hash_or_array ]
105
-
106
- inflection = if options[:action] && options[:action].to_s == "new"
107
- args.pop
108
- :singular
109
- elsif (record.respond_to?(:persisted?) && !record.persisted?)
110
- args.pop
111
- :plural
112
- elsif record.is_a?(Class)
113
- args.pop
114
- :plural
115
- else
116
- :singular
117
- end
110
+ opts = options.dup
111
+ action = opts.delete :action
112
+ type = opts.delete(:routing_type) || :url
118
113
 
119
- args.delete_if {|arg| arg.is_a?(Symbol) || arg.is_a?(String)}
120
- named_route = build_named_route_call(record_or_hash_or_array, inflection, options)
114
+ HelperMethodBuilder.polymorphic_method self,
115
+ record_or_hash_or_array,
116
+ action,
117
+ type,
118
+ opts
119
+ end
121
120
 
122
- url_options = options.except(:action, :routing_type)
123
- unless url_options.empty?
124
- args.last.kind_of?(Hash) ? args.last.merge!(url_options) : args << url_options
121
+ # Returns the path component of a URL for the given record. It uses
122
+ # <tt>polymorphic_url</tt> with <tt>routing_type: :path</tt>.
123
+ def polymorphic_path(record_or_hash_or_array, options = {})
124
+ if Hash === record_or_hash_or_array
125
+ options = record_or_hash_or_array.merge(options)
126
+ record = options.delete :id
127
+ return polymorphic_path record, options
125
128
  end
126
129
 
127
- args.collect! { |a| convert_to_model(a) }
130
+ opts = options.dup
131
+ action = opts.delete :action
132
+ type = :path
128
133
 
129
- (proxy || self).send(named_route, *args)
134
+ HelperMethodBuilder.polymorphic_method self,
135
+ record_or_hash_or_array,
136
+ action,
137
+ type,
138
+ opts
130
139
  end
131
140
 
132
- # Returns the path component of a URL for the given record. It uses
133
- # <tt>polymorphic_url</tt> with <tt>:routing_type => :path</tt>.
134
- def polymorphic_path(record_or_hash_or_array, options = {})
135
- polymorphic_url(record_or_hash_or_array, options.merge(:routing_type => :path))
136
- end
137
141
 
138
142
  %w(edit new).each do |action|
139
143
  module_eval <<-EOT, __FILE__, __LINE__ + 1
140
- def #{action}_polymorphic_url(record_or_hash, options = {}) # def edit_polymorphic_url(record_or_hash, options = {})
141
- polymorphic_url( # polymorphic_url(
142
- record_or_hash, # record_or_hash,
143
- options.merge(:action => "#{action}")) # options.merge(:action => "edit"))
144
- end # end
145
- #
146
- def #{action}_polymorphic_path(record_or_hash, options = {}) # def edit_polymorphic_path(record_or_hash, options = {})
147
- polymorphic_url( # polymorphic_url(
148
- record_or_hash, # record_or_hash,
149
- options.merge(:action => "#{action}", :routing_type => :path)) # options.merge(:action => "edit", :routing_type => :path))
150
- end # end
144
+ def #{action}_polymorphic_url(record_or_hash, options = {})
145
+ polymorphic_url_for_action("#{action}", record_or_hash, options)
146
+ end
147
+
148
+ def #{action}_polymorphic_path(record_or_hash, options = {})
149
+ polymorphic_path_for_action("#{action}", record_or_hash, options)
150
+ end
151
151
  EOT
152
152
  end
153
153
 
154
154
  private
155
- def action_prefix(options)
156
- options[:action] ? "#{options[:action]}_" : ''
155
+
156
+ def polymorphic_url_for_action(action, record_or_hash, options)
157
+ polymorphic_url(record_or_hash, options.merge(:action => action))
158
+ end
159
+
160
+ def polymorphic_path_for_action(action, record_or_hash, options)
161
+ polymorphic_path(record_or_hash, options.merge(:action => action))
162
+ end
163
+
164
+ class HelperMethodBuilder # :nodoc:
165
+ CACHE = { 'path' => {}, 'url' => {} }
166
+
167
+ def self.get(action, type)
168
+ type = type.to_s
169
+ CACHE[type].fetch(action) { build action, type }
170
+ end
171
+
172
+ def self.url; CACHE['url'.freeze][nil]; end
173
+ def self.path; CACHE['path'.freeze][nil]; end
174
+
175
+ def self.build(action, type)
176
+ prefix = action ? "#{action}_" : ""
177
+ suffix = type
178
+ if action.to_s == 'new'
179
+ HelperMethodBuilder.singular prefix, suffix
180
+ else
181
+ HelperMethodBuilder.plural prefix, suffix
182
+ end
157
183
  end
158
184
 
159
- def convert_to_model(object)
160
- object.respond_to?(:to_model) ? object.to_model : object
185
+ def self.singular(prefix, suffix)
186
+ new(->(name) { name.singular_route_key }, prefix, suffix)
161
187
  end
162
188
 
163
- def routing_type(options)
164
- options[:routing_type] || :url
189
+ def self.plural(prefix, suffix)
190
+ new(->(name) { name.route_key }, prefix, suffix)
165
191
  end
166
192
 
167
- def build_named_route_call(records, inflection, options = {})
168
- if records.is_a?(Array)
169
- record = records.pop
170
- route = records.map do |parent|
171
- if parent.is_a?(Symbol) || parent.is_a?(String)
172
- parent
173
- else
174
- ActiveModel::Naming.singular_route_key(parent)
175
- end
193
+ def self.polymorphic_method(recipient, record_or_hash_or_array, action, type, options)
194
+ builder = get action, type
195
+
196
+ case record_or_hash_or_array
197
+ when Array
198
+ record_or_hash_or_array = record_or_hash_or_array.compact
199
+ if record_or_hash_or_array.empty?
200
+ raise ArgumentError, "Nil location provided. Can't build URI."
201
+ end
202
+ if record_or_hash_or_array.first.is_a?(ActionDispatch::Routing::RoutesProxy)
203
+ recipient = record_or_hash_or_array.shift
176
204
  end
205
+
206
+ method, args = builder.handle_list record_or_hash_or_array
207
+ when String, Symbol
208
+ method, args = builder.handle_string record_or_hash_or_array
209
+ when Class
210
+ method, args = builder.handle_class record_or_hash_or_array
211
+
212
+ when nil
213
+ raise ArgumentError, "Nil location provided. Can't build URI."
214
+ else
215
+ method, args = builder.handle_model record_or_hash_or_array
216
+ end
217
+
218
+
219
+ if options.empty?
220
+ recipient.send(method, *args)
177
221
  else
178
- record = extract_record(records)
179
- route = []
222
+ recipient.send(method, *args, options)
180
223
  end
224
+ end
225
+
226
+ attr_reader :suffix, :prefix
181
227
 
182
- if record.is_a?(Symbol) || record.is_a?(String)
183
- route << record
184
- elsif record
185
- if inflection == :singular
186
- route << ActiveModel::Naming.singular_route_key(record)
228
+ def initialize(key_strategy, prefix, suffix)
229
+ @key_strategy = key_strategy
230
+ @prefix = prefix
231
+ @suffix = suffix
232
+ end
233
+
234
+ def handle_string(record)
235
+ [get_method_for_string(record), []]
236
+ end
237
+
238
+ def handle_string_call(target, str)
239
+ target.send get_method_for_string str
240
+ end
241
+
242
+ def handle_class(klass)
243
+ [get_method_for_class(klass), []]
244
+ end
245
+
246
+ def handle_class_call(target, klass)
247
+ target.send get_method_for_class klass
248
+ end
249
+
250
+ def handle_model(record)
251
+ args = []
252
+
253
+ model = record.to_model
254
+ name = if model.persisted?
255
+ args << model
256
+ model.model_name.singular_route_key
257
+ else
258
+ @key_strategy.call model.model_name
259
+ end
260
+
261
+ named_route = prefix + "#{name}_#{suffix}"
262
+
263
+ [named_route, args]
264
+ end
265
+
266
+ def handle_model_call(target, model)
267
+ method, args = handle_model model
268
+ target.send(method, *args)
269
+ end
270
+
271
+ def handle_list(list)
272
+ record_list = list.dup
273
+ record = record_list.pop
274
+
275
+ args = []
276
+
277
+ route = record_list.map { |parent|
278
+ case parent
279
+ when Symbol, String
280
+ parent.to_s
281
+ when Class
282
+ args << parent
283
+ parent.model_name.singular_route_key
187
284
  else
188
- route << ActiveModel::Naming.route_key(record)
285
+ args << parent.to_model
286
+ parent.to_model.model_name.singular_route_key
189
287
  end
288
+ }
289
+
290
+ route <<
291
+ case record
292
+ when Symbol, String
293
+ record.to_s
294
+ when Class
295
+ @key_strategy.call record.model_name
190
296
  else
191
- raise ArgumentError, "Nil location provided. Can't build URI."
297
+ model = record.to_model
298
+ if model.persisted?
299
+ args << model
300
+ model.model_name.singular_route_key
301
+ else
302
+ @key_strategy.call model.model_name
303
+ end
192
304
  end
193
305
 
194
- route << routing_type(options)
306
+ route << suffix
195
307
 
196
- action_prefix(options) + route.join("_")
308
+ named_route = prefix + route.join("_")
309
+ [named_route, args]
197
310
  end
198
311
 
199
- def extract_record(record_or_hash_or_array)
200
- case record_or_hash_or_array
201
- when Array; record_or_hash_or_array.last
202
- when Hash; record_or_hash_or_array[:id]
203
- else record_or_hash_or_array
204
- end
312
+ private
313
+
314
+ def get_method_for_class(klass)
315
+ name = @key_strategy.call klass.model_name
316
+ prefix + "#{name}_#{suffix}"
317
+ end
318
+
319
+ def get_method_for_string(str)
320
+ prefix + "#{str}_#{suffix}"
205
321
  end
322
+
323
+ [nil, 'new', 'edit'].each do |action|
324
+ CACHE['url'][action] = build action, 'url'
325
+ CACHE['path'][action] = build action, 'path'
326
+ end
327
+ end
206
328
  end
207
329
  end
208
330
  end
209
-
@@ -1,10 +1,13 @@
1
1
  require 'action_dispatch/http/request'
2
2
  require 'active_support/core_ext/uri'
3
+ require 'active_support/core_ext/array/extract_options'
3
4
  require 'rack/utils'
5
+ require 'action_controller/metal/exceptions'
6
+ require 'action_dispatch/routing/endpoint'
4
7
 
5
8
  module ActionDispatch
6
9
  module Routing
7
- class Redirect # :nodoc:
10
+ class Redirect < Endpoint # :nodoc:
8
11
  attr_reader :status, :block
9
12
 
10
13
  def initialize(status, block)
@@ -12,15 +15,29 @@ module ActionDispatch
12
15
  @block = block
13
16
  end
14
17
 
18
+ def redirect?; true; end
19
+
15
20
  def call(env)
16
- req = Request.new(env)
21
+ serve Request.new env
22
+ end
17
23
 
18
- uri = URI.parse(path(req.symbolized_path_parameters, req))
24
+ def serve(req)
25
+ req.check_path_parameters!
26
+ uri = URI.parse(path(req.path_parameters, req))
27
+
28
+ unless uri.host
29
+ if relative_path?(uri.path)
30
+ uri.path = "#{req.script_name}/#{uri.path}"
31
+ elsif uri.path.empty?
32
+ uri.path = req.script_name.empty? ? "/" : req.script_name
33
+ end
34
+ end
35
+
19
36
  uri.scheme ||= req.scheme
20
37
  uri.host ||= req.host
21
38
  uri.port ||= req.port unless req.standard_port?
22
39
 
23
- body = %(<html><body>You are being <a href="#{ERB::Util.h(uri.to_s)}">redirected</a>.</body></html>)
40
+ body = %(<html><body>You are being <a href="#{ERB::Util.unwrapped_html_escape(uri.to_s)}">redirected</a>.</body></html>)
24
41
 
25
42
  headers = {
26
43
  'Location' => uri.to_s,
@@ -34,6 +51,52 @@ module ActionDispatch
34
51
  def path(params, request)
35
52
  block.call params, request
36
53
  end
54
+
55
+ def inspect
56
+ "redirect(#{status})"
57
+ end
58
+
59
+ private
60
+ def relative_path?(path)
61
+ path && !path.empty? && path[0] != '/'
62
+ end
63
+
64
+ def escape(params)
65
+ Hash[params.map{ |k,v| [k, Rack::Utils.escape(v)] }]
66
+ end
67
+
68
+ def escape_fragment(params)
69
+ Hash[params.map{ |k,v| [k, Journey::Router::Utils.escape_fragment(v)] }]
70
+ end
71
+
72
+ def escape_path(params)
73
+ Hash[params.map{ |k,v| [k, Journey::Router::Utils.escape_path(v)] }]
74
+ end
75
+ end
76
+
77
+ class PathRedirect < Redirect
78
+ URL_PARTS = /\A([^?]+)?(\?[^#]+)?(#.+)?\z/
79
+
80
+ def path(params, request)
81
+ if block.match(URL_PARTS)
82
+ path = interpolation_required?($1, params) ? $1 % escape_path(params) : $1
83
+ query = interpolation_required?($2, params) ? $2 % escape(params) : $2
84
+ fragment = interpolation_required?($3, params) ? $3 % escape_fragment(params) : $3
85
+
86
+ "#{path}#{query}#{fragment}"
87
+ else
88
+ interpolation_required?(block, params) ? block % escape(params) : block
89
+ end
90
+ end
91
+
92
+ def inspect
93
+ "redirect(#{status}, #{block})"
94
+ end
95
+
96
+ private
97
+ def interpolation_required?(string, params)
98
+ !params.empty? && string && string.match(/%\{\w*\}/)
99
+ end
37
100
  end
38
101
 
39
102
  class OptionRedirect < Redirect # :nodoc:
@@ -46,30 +109,43 @@ module ActionDispatch
46
109
  :port => request.optional_port,
47
110
  :path => request.path,
48
111
  :params => request.query_parameters
49
- }.merge options
112
+ }.merge! options
50
113
 
51
114
  if !params.empty? && url_options[:path].match(/%\{\w*\}/)
52
115
  url_options[:path] = (url_options[:path] % escape_path(params))
53
116
  end
54
117
 
118
+ unless options[:host] || options[:domain]
119
+ if relative_path?(url_options[:path])
120
+ url_options[:path] = "/#{url_options[:path]}"
121
+ url_options[:script_name] = request.script_name
122
+ elsif url_options[:path].empty?
123
+ url_options[:path] = request.script_name.empty? ? "/" : ""
124
+ url_options[:script_name] = request.script_name
125
+ end
126
+ end
127
+
55
128
  ActionDispatch::Http::URL.url_for url_options
56
129
  end
57
130
 
58
- private
59
- def escape_path(params)
60
- Hash[params.map{ |k,v| [k, URI.parser.escape(v)] }]
61
- end
131
+ def inspect
132
+ "redirect(#{status}, #{options.map{ |k,v| "#{k}: #{v}" }.join(', ')})"
133
+ end
62
134
  end
63
135
 
64
136
  module Redirection
65
137
 
66
138
  # Redirect any path to another path:
67
139
  #
68
- # match "/stories" => redirect("/posts")
140
+ # get "/stories" => redirect("/posts")
69
141
  #
70
142
  # You can also use interpolation in the supplied redirect argument:
71
143
  #
72
- # match 'docs/:article', :to => redirect('/wiki/%{article}')
144
+ # get 'docs/:article', to: redirect('/wiki/%{article}')
145
+ #
146
+ # Note that if you return a path without a leading slash then the url is prefixed with the
147
+ # current SCRIPT_NAME environment variable. This is typically '/' but may be different in
148
+ # a mounted engine or where the application is deployed to a subdirectory of a website.
73
149
  #
74
150
  # Alternatively you can use one of the other syntaxes:
75
151
  #
@@ -78,54 +154,38 @@ module ActionDispatch
78
154
  # params, depending of how many arguments your block accepts. A string is required as a
79
155
  # return value.
80
156
  #
81
- # match 'jokes/:number', :to => redirect { |params, request|
157
+ # get 'jokes/:number', to: redirect { |params, request|
82
158
  # path = (params[:number].to_i.even? ? "wheres-the-beef" : "i-love-lamp")
83
159
  # "http://#{request.host_with_port}/#{path}"
84
160
  # }
85
161
  #
162
+ # Note that the +do end+ syntax for the redirect block wouldn't work, as Ruby would pass
163
+ # the block to +get+ instead of +redirect+. Use <tt>{ ... }</tt> instead.
164
+ #
86
165
  # The options version of redirect allows you to supply only the parts of the url which need
87
166
  # to change, it also supports interpolation of the path similar to the first example.
88
167
  #
89
- # match 'stores/:name', :to => redirect(:subdomain => 'stores', :path => '/%{name}')
90
- # match 'stores/:name(*all)', :to => redirect(:subdomain => 'stores', :path => '/%{name}%{all}')
168
+ # get 'stores/:name', to: redirect(subdomain: 'stores', path: '/%{name}')
169
+ # get 'stores/:name(*all)', to: redirect(subdomain: 'stores', path: '/%{name}%{all}')
91
170
  #
92
171
  # Finally, an object which responds to call can be supplied to redirect, allowing you to reuse
93
172
  # common redirect routes. The call method must accept two arguments, params and request, and return
94
173
  # a string.
95
174
  #
96
- # match 'accounts/:name' => redirect(SubdomainRedirector.new('api'))
175
+ # get 'accounts/:name' => redirect(SubdomainRedirector.new('api'))
97
176
  #
98
177
  def redirect(*args, &block)
99
- options = args.last.is_a?(Hash) ? args.pop : {}
178
+ options = args.extract_options!
100
179
  status = options.delete(:status) || 301
180
+ path = args.shift
101
181
 
102
182
  return OptionRedirect.new(status, options) if options.any?
103
-
104
- path = args.shift
105
-
106
- block = lambda { |params, request|
107
- (params.empty? || !path.match(/%\{\w*\}/)) ? path : (path % escape(params))
108
- } if String === path
183
+ return PathRedirect.new(status, path) if String === path
109
184
 
110
185
  block = path if path.respond_to? :call
111
-
112
- # :FIXME: remove in Rails 4.0
113
- if block && block.respond_to?(:arity) && block.arity < 2
114
- msg = "redirect blocks with arity of #{block.arity} are deprecated. Your block must take 2 parameters: the environment, and a request object"
115
- ActiveSupport::Deprecation.warn msg
116
- deprecated_block = block
117
- block = lambda { |params, _| deprecated_block.call(params) }
118
- end
119
-
120
186
  raise ArgumentError, "redirection argument not supported" unless block
121
-
122
187
  Redirect.new status, block
123
188
  end
124
-
125
- private
126
- def escape(params)
127
- Hash[params.map{ |k,v| [k, Rack::Utils.escape(v)] }]
128
- end
129
189
  end
130
190
  end
131
191
  end