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.
- data/CHANGELOG +433 -375
- data/MIT-LICENSE +1 -1
- data/README +21 -75
- data/Rakefile +1 -1
- data/lib/action_controller.rb +80 -43
- data/lib/action_controller/assertions/model_assertions.rb +1 -0
- data/lib/action_controller/assertions/response_assertions.rb +43 -16
- data/lib/action_controller/assertions/routing_assertions.rb +1 -1
- data/lib/action_controller/assertions/selector_assertions.rb +17 -12
- data/lib/action_controller/assertions/tag_assertions.rb +1 -4
- data/lib/action_controller/base.rb +153 -82
- data/lib/action_controller/benchmarking.rb +9 -9
- data/lib/action_controller/caching.rb +9 -11
- data/lib/action_controller/caching/actions.rb +11 -18
- data/lib/action_controller/caching/fragments.rb +28 -20
- data/lib/action_controller/caching/pages.rb +13 -15
- data/lib/action_controller/caching/sweeping.rb +2 -2
- data/lib/action_controller/cgi_ext.rb +0 -1
- data/lib/action_controller/cgi_ext/cookie.rb +2 -0
- data/lib/action_controller/cgi_process.rb +54 -162
- data/lib/action_controller/cookies.rb +13 -25
- data/lib/action_controller/dispatcher.rb +43 -122
- data/lib/action_controller/failsafe.rb +52 -0
- data/lib/action_controller/flash.rb +38 -47
- data/lib/action_controller/helpers.rb +13 -9
- data/lib/action_controller/http_authentication.rb +203 -23
- data/lib/action_controller/integration.rb +126 -70
- data/lib/action_controller/layout.rb +36 -39
- data/lib/action_controller/middleware_stack.rb +119 -0
- data/lib/action_controller/middlewares.rb +13 -0
- data/lib/action_controller/mime_responds.rb +19 -4
- data/lib/action_controller/mime_type.rb +8 -0
- data/lib/action_controller/params_parser.rb +71 -0
- data/lib/action_controller/performance_test.rb +0 -1
- data/lib/action_controller/polymorphic_routes.rb +36 -30
- data/lib/action_controller/reloader.rb +14 -0
- data/lib/action_controller/request.rb +107 -499
- data/lib/action_controller/request_forgery_protection.rb +7 -39
- data/lib/action_controller/rescue.rb +55 -35
- data/lib/action_controller/resources.rb +34 -31
- data/lib/action_controller/response.rb +99 -57
- data/lib/action_controller/rewindable_input.rb +28 -0
- data/lib/action_controller/routing.rb +7 -7
- data/lib/action_controller/routing/builder.rb +4 -1
- data/lib/action_controller/routing/optimisations.rb +1 -1
- data/lib/action_controller/routing/recognition_optimisation.rb +1 -2
- data/lib/action_controller/routing/route.rb +15 -5
- data/lib/action_controller/routing/route_set.rb +82 -35
- data/lib/action_controller/routing/segments.rb +35 -0
- data/lib/action_controller/session/abstract_store.rb +181 -0
- data/lib/action_controller/session/cookie_store.rb +197 -175
- data/lib/action_controller/session/mem_cache_store.rb +36 -83
- data/lib/action_controller/session_management.rb +26 -134
- data/lib/action_controller/streaming.rb +24 -7
- data/lib/action_controller/templates/rescues/diagnostics.erb +2 -2
- data/lib/action_controller/templates/rescues/template_error.erb +2 -2
- data/lib/action_controller/test_case.rb +87 -30
- data/lib/action_controller/test_process.rb +145 -104
- data/lib/action_controller/uploaded_file.rb +44 -0
- data/lib/action_controller/url_rewriter.rb +3 -6
- data/lib/action_controller/vendor/html-scanner.rb +16 -0
- data/lib/action_controller/vendor/html-scanner/html/selector.rb +1 -1
- data/lib/action_controller/vendor/rack-1.0/rack.rb +89 -0
- data/lib/action_controller/vendor/rack-1.0/rack/adapter/camping.rb +22 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/handler.rb +37 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/request.rb +37 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/basic.rb +58 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/md5.rb +124 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/nonce.rb +51 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/params.rb +55 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/request.rb +40 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/openid.rb +480 -0
- data/lib/action_controller/vendor/rack-1.0/rack/builder.rb +63 -0
- data/lib/action_controller/vendor/rack-1.0/rack/cascade.rb +36 -0
- data/lib/action_controller/vendor/rack-1.0/rack/chunked.rb +49 -0
- data/lib/action_controller/vendor/rack-1.0/rack/commonlogger.rb +61 -0
- data/lib/action_controller/vendor/rack-1.0/rack/conditionalget.rb +45 -0
- data/lib/action_controller/vendor/rack-1.0/rack/content_length.rb +29 -0
- data/lib/action_controller/vendor/rack-1.0/rack/content_type.rb +23 -0
- data/lib/action_controller/vendor/rack-1.0/rack/deflater.rb +85 -0
- data/lib/action_controller/vendor/rack-1.0/rack/directory.rb +153 -0
- data/lib/action_controller/vendor/rack-1.0/rack/file.rb +88 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler.rb +48 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/cgi.rb +61 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/evented_mongrel.rb +8 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/fastcgi.rb +89 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/lsws.rb +55 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/mongrel.rb +84 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/scgi.rb +59 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/swiftiplied_mongrel.rb +8 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/thin.rb +18 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/webrick.rb +67 -0
- data/lib/action_controller/vendor/rack-1.0/rack/head.rb +19 -0
- data/lib/action_controller/vendor/rack-1.0/rack/lint.rb +462 -0
- data/lib/action_controller/vendor/rack-1.0/rack/lobster.rb +65 -0
- data/lib/action_controller/vendor/rack-1.0/rack/lock.rb +16 -0
- data/lib/action_controller/vendor/rack-1.0/rack/methodoverride.rb +27 -0
- data/lib/action_controller/vendor/rack-1.0/rack/mime.rb +204 -0
- data/lib/action_controller/vendor/rack-1.0/rack/mock.rb +160 -0
- data/lib/action_controller/vendor/rack-1.0/rack/recursive.rb +57 -0
- data/lib/action_controller/vendor/rack-1.0/rack/reloader.rb +64 -0
- data/lib/action_controller/vendor/rack-1.0/rack/request.rb +241 -0
- data/lib/action_controller/vendor/rack-1.0/rack/response.rb +179 -0
- data/lib/action_controller/vendor/rack-1.0/rack/session/abstract/id.rb +142 -0
- data/lib/action_controller/vendor/rack-1.0/rack/session/cookie.rb +91 -0
- data/lib/action_controller/vendor/rack-1.0/rack/session/memcache.rb +109 -0
- data/lib/action_controller/vendor/rack-1.0/rack/session/pool.rb +100 -0
- data/lib/action_controller/vendor/rack-1.0/rack/showexceptions.rb +349 -0
- data/lib/action_controller/vendor/rack-1.0/rack/showstatus.rb +106 -0
- data/lib/action_controller/vendor/rack-1.0/rack/static.rb +38 -0
- data/lib/action_controller/vendor/rack-1.0/rack/urlmap.rb +55 -0
- data/lib/action_controller/vendor/rack-1.0/rack/utils.rb +392 -0
- data/lib/action_controller/verification.rb +1 -1
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/version.rb +2 -2
- data/lib/action_view.rb +22 -17
- data/lib/action_view/base.rb +53 -79
- data/lib/action_view/erb/util.rb +38 -0
- data/lib/action_view/helpers.rb +24 -5
- data/lib/action_view/helpers/active_record_helper.rb +2 -2
- data/lib/action_view/helpers/asset_tag_helper.rb +81 -50
- data/lib/action_view/helpers/atom_feed_helper.rb +1 -1
- data/lib/action_view/helpers/benchmark_helper.rb +26 -5
- data/lib/action_view/helpers/date_helper.rb +82 -7
- data/lib/action_view/helpers/form_helper.rb +295 -64
- data/lib/action_view/helpers/form_options_helper.rb +160 -18
- data/lib/action_view/helpers/form_tag_helper.rb +2 -2
- data/lib/action_view/helpers/number_helper.rb +31 -18
- data/lib/action_view/helpers/prototype_helper.rb +2 -12
- data/lib/action_view/helpers/sanitize_helper.rb +0 -10
- data/lib/action_view/helpers/scriptaculous_helper.rb +1 -0
- data/lib/action_view/helpers/tag_helper.rb +3 -4
- data/lib/action_view/helpers/text_helper.rb +99 -122
- data/lib/action_view/helpers/translation_helper.rb +19 -1
- data/lib/action_view/helpers/url_helper.rb +25 -2
- data/lib/action_view/inline_template.rb +1 -1
- data/lib/action_view/locale/en.yml +19 -1
- data/lib/action_view/partials.rb +46 -9
- data/lib/action_view/paths.rb +28 -84
- data/lib/action_view/reloadable_template.rb +117 -0
- data/lib/action_view/renderable.rb +28 -35
- data/lib/action_view/renderable_partial.rb +3 -4
- data/lib/action_view/template.rb +172 -31
- data/lib/action_view/template_error.rb +8 -9
- data/lib/action_view/template_handler.rb +1 -1
- data/lib/action_view/template_handlers.rb +9 -6
- data/lib/action_view/template_handlers/erb.rb +2 -39
- data/lib/action_view/template_handlers/rjs.rb +1 -0
- data/lib/action_view/test_case.rb +27 -1
- data/test/abstract_unit.rb +23 -17
- data/test/active_record_unit.rb +5 -4
- data/test/activerecord/active_record_store_test.rb +139 -106
- data/test/activerecord/render_partial_with_record_identification_test.rb +5 -21
- data/test/controller/action_pack_assertions_test.rb +25 -23
- data/test/controller/addresses_render_test.rb +3 -6
- data/test/controller/assert_select_test.rb +83 -70
- data/test/controller/base_test.rb +11 -13
- data/test/controller/benchmark_test.rb +3 -3
- data/test/controller/caching_test.rb +34 -24
- data/test/controller/capture_test.rb +3 -6
- data/test/controller/content_type_test.rb +3 -6
- data/test/controller/cookie_test.rb +31 -66
- data/test/controller/deprecation/deprecated_base_methods_test.rb +9 -11
- data/test/controller/dispatcher_test.rb +23 -28
- data/test/controller/fake_models.rb +8 -0
- data/test/controller/filters_test.rb +6 -2
- data/test/controller/flash_test.rb +2 -6
- data/test/controller/helper_test.rb +15 -1
- data/test/controller/html-scanner/document_test.rb +1 -1
- data/test/controller/html-scanner/sanitizer_test.rb +1 -1
- data/test/controller/http_basic_authentication_test.rb +88 -0
- data/test/controller/http_digest_authentication_test.rb +178 -0
- data/test/controller/integration_test.rb +56 -52
- data/test/controller/layout_test.rb +46 -44
- data/test/controller/middleware_stack_test.rb +90 -0
- data/test/controller/mime_responds_test.rb +7 -11
- data/test/controller/mime_type_test.rb +9 -0
- data/test/controller/polymorphic_routes_test.rb +235 -151
- data/test/controller/rack_test.rb +52 -81
- data/test/controller/redirect_test.rb +6 -14
- data/test/controller/render_test.rb +273 -60
- data/test/controller/request/json_params_parsing_test.rb +45 -0
- data/test/controller/request/multipart_params_parsing_test.rb +223 -0
- data/test/controller/request/query_string_parsing_test.rb +120 -0
- data/test/controller/request/url_encoded_params_parsing_test.rb +184 -0
- data/test/controller/request/xml_params_parsing_test.rb +88 -0
- data/test/controller/request_forgery_protection_test.rb +17 -98
- data/test/controller/request_test.rb +45 -530
- data/test/controller/rescue_test.rb +45 -22
- data/test/controller/resources_test.rb +112 -37
- data/test/controller/routing_test.rb +1442 -1384
- data/test/controller/selector_test.rb +3 -3
- data/test/controller/send_file_test.rb +30 -3
- data/test/controller/session/cookie_store_test.rb +169 -240
- data/test/controller/session/mem_cache_store_test.rb +94 -148
- data/test/controller/session/test_session_test.rb +58 -0
- data/test/controller/test_test.rb +32 -13
- data/test/controller/url_rewriter_test.rb +54 -4
- data/test/controller/verification_test.rb +1 -1
- data/test/controller/view_paths_test.rb +15 -15
- data/test/controller/webservice_test.rb +178 -147
- data/test/fixtures/alternate_helpers/foo_helper.rb +3 -0
- data/test/fixtures/layout_tests/alt/layouts/alt.rhtml +0 -0
- data/test/fixtures/layouts/default_html.html.erb +1 -0
- data/test/fixtures/layouts/xhr.html.erb +2 -0
- data/test/fixtures/multipart/empty +10 -0
- data/test/fixtures/multipart/hello.txt +1 -0
- data/test/fixtures/multipart/none +9 -0
- data/test/fixtures/public/500.da.html +1 -0
- data/test/fixtures/quiz/questions/_question.html.erb +1 -0
- data/test/fixtures/replies.yml +1 -1
- data/test/fixtures/test/_one.html.erb +1 -0
- data/test/fixtures/test/_two.html.erb +1 -0
- data/test/fixtures/test/dont_pick_me +1 -0
- data/test/fixtures/test/hello.builder +1 -1
- data/test/fixtures/test/hello_world.da.html.erb +1 -0
- data/test/fixtures/test/hello_world.erb~ +1 -0
- data/test/fixtures/test/hello_world.pt-BR.html.erb +1 -0
- data/test/fixtures/test/malformed/malformed.en.html.erb~ +1 -0
- data/test/fixtures/test/malformed/malformed.erb~ +1 -0
- data/test/fixtures/test/malformed/malformed.html.erb~ +1 -0
- data/test/fixtures/test/render_explicit_html_template.js.rjs +1 -0
- data/test/fixtures/test/render_implicit_html_template.js.rjs +1 -0
- data/test/fixtures/test/render_implicit_html_template_from_xhr_request.da.html.erb +1 -0
- data/test/fixtures/test/render_implicit_html_template_from_xhr_request.html.erb +1 -0
- data/test/fixtures/test/render_implicit_js_template_without_layout.js.erb +1 -0
- data/test/fixtures/test/utf8.html.erb +2 -0
- data/test/template/active_record_helper_i18n_test.rb +31 -33
- data/test/template/active_record_helper_test.rb +34 -0
- data/test/template/asset_tag_helper_test.rb +52 -14
- data/test/template/atom_feed_helper_test.rb +3 -5
- data/test/template/benchmark_helper_test.rb +50 -24
- data/test/template/compiled_templates_test.rb +177 -33
- data/test/template/date_helper_i18n_test.rb +88 -81
- data/test/template/date_helper_test.rb +427 -43
- data/test/template/form_helper_test.rb +243 -44
- data/test/template/form_options_helper_test.rb +631 -565
- data/test/template/form_tag_helper_test.rb +9 -2
- data/test/template/javascript_helper_test.rb +0 -5
- data/test/template/number_helper_i18n_test.rb +60 -48
- data/test/template/number_helper_test.rb +1 -0
- data/test/template/render_test.rb +117 -35
- data/test/template/test_test.rb +4 -6
- data/test/template/text_helper_test.rb +129 -50
- data/test/template/translation_helper_test.rb +23 -19
- data/test/template/url_helper_test.rb +35 -2
- data/test/view/test_case_test.rb +8 -0
- metadata +197 -23
- data/lib/action_controller/assertions.rb +0 -69
- data/lib/action_controller/caching/sql_cache.rb +0 -18
- data/lib/action_controller/cgi_ext/session.rb +0 -53
- data/lib/action_controller/components.rb +0 -169
- data/lib/action_controller/rack_process.rb +0 -297
- data/lib/action_controller/request_profiler.rb +0 -169
- data/lib/action_controller/session/active_record_store.rb +0 -340
- data/lib/action_controller/session/drb_server.rb +0 -32
- data/lib/action_controller/session/drb_store.rb +0 -35
- data/test/controller/cgi_test.rb +0 -269
- data/test/controller/components_test.rb +0 -156
- data/test/controller/http_authentication_test.rb +0 -54
- data/test/controller/integration_upload_test.rb +0 -43
- data/test/controller/session_fixation_test.rb +0 -89
- data/test/controller/session_management_test.rb +0 -178
- data/test/fixtures/test/hello_world.js +0 -1
@@ -0,0 +1,28 @@
|
|
1
|
+
module ActionController
|
2
|
+
class RewindableInput
|
3
|
+
class RewindableIO < ActiveSupport::BasicObject
|
4
|
+
def initialize(io)
|
5
|
+
@io = io
|
6
|
+
@rewindable = io.is_a?(::StringIO)
|
7
|
+
end
|
8
|
+
|
9
|
+
def method_missing(method, *args, &block)
|
10
|
+
unless @rewindable
|
11
|
+
@io = ::StringIO.new(@io.read)
|
12
|
+
@rewindable = true
|
13
|
+
end
|
14
|
+
|
15
|
+
@io.__send__(method, *args, &block)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(app)
|
20
|
+
@app = app
|
21
|
+
end
|
22
|
+
|
23
|
+
def call(env)
|
24
|
+
env['rack.input'] = RewindableIO.new(env['rack.input'])
|
25
|
+
@app.call(env)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'cgi'
|
2
2
|
require 'uri'
|
3
|
-
require 'action_controller/polymorphic_routes'
|
4
3
|
require 'action_controller/routing/optimisations'
|
5
4
|
require 'action_controller/routing/routing_ext'
|
6
5
|
require 'action_controller/routing/route'
|
@@ -84,9 +83,11 @@ module ActionController
|
|
84
83
|
# This sets up +blog+ as the default controller if no other is specified.
|
85
84
|
# This means visiting '/' would invoke the blog controller.
|
86
85
|
#
|
87
|
-
# More formally, you can
|
86
|
+
# More formally, you can include arbitrary parameters in the route, thus:
|
88
87
|
#
|
89
|
-
# map.connect ':controller/:action/:id', :action => 'show', :
|
88
|
+
# map.connect ':controller/:action/:id', :action => 'show', :page => 'Dashboard'
|
89
|
+
#
|
90
|
+
# This will pass the :page parameter to all incoming requests that match this route.
|
90
91
|
#
|
91
92
|
# Note: The default routes, as provided by the Rails generator, make all actions in every
|
92
93
|
# controller accessible via GET requests. You should consider removing them or commenting
|
@@ -192,9 +193,8 @@ module ActionController
|
|
192
193
|
#
|
193
194
|
# map.connect '*path' , :controller => 'blog' , :action => 'unrecognized?'
|
194
195
|
#
|
195
|
-
# will glob all remaining parts of the route that were not recognized earlier.
|
196
|
-
#
|
197
|
-
# this case.
|
196
|
+
# will glob all remaining parts of the route that were not recognized earlier.
|
197
|
+
# The globbed values are in <tt>params[:path]</tt> as an array of path segments.
|
198
198
|
#
|
199
199
|
# == Route conditions
|
200
200
|
#
|
@@ -267,7 +267,7 @@ module ActionController
|
|
267
267
|
module Routing
|
268
268
|
SEPARATORS = %w( / . ? )
|
269
269
|
|
270
|
-
HTTP_METHODS = [:get, :head, :post, :put, :delete]
|
270
|
+
HTTP_METHODS = [:get, :head, :post, :put, :delete, :options]
|
271
271
|
|
272
272
|
ALLOWED_REQUIREMENTS_FOR_OPTIMISATION = [:controller, :action].to_set
|
273
273
|
|
@@ -34,6 +34,8 @@ module ActionController
|
|
34
34
|
def segment_for(string)
|
35
35
|
segment =
|
36
36
|
case string
|
37
|
+
when /\A\.(:format)?\//
|
38
|
+
OptionalFormatSegment.new
|
37
39
|
when /\A:(\w+)/
|
38
40
|
key = $1.to_sym
|
39
41
|
key == :controller ? ControllerSegment.new(key) : DynamicSegment.new(key)
|
@@ -157,7 +159,8 @@ module ActionController
|
|
157
159
|
path = "/#{path}" unless path[0] == ?/
|
158
160
|
path = "#{path}/" unless path[-1] == ?/
|
159
161
|
|
160
|
-
|
162
|
+
prefix = options[:path_prefix].to_s.gsub(/^\//,'')
|
163
|
+
path = "/#{prefix}#{path}" unless prefix.blank?
|
161
164
|
|
162
165
|
segments = segments_for_route_path(path)
|
163
166
|
defaults, requirements, conditions = divide_route_options(segments, options)
|
@@ -65,7 +65,7 @@ module ActionController
|
|
65
65
|
# rather than triggering the expensive logic in +url_for+.
|
66
66
|
class PositionalArguments < Optimiser
|
67
67
|
def guard_conditions
|
68
|
-
number_of_arguments = route.
|
68
|
+
number_of_arguments = route.required_segment_keys.size
|
69
69
|
# if they're using foo_url(:id=>2) it's one
|
70
70
|
# argument, but we don't want to generate /foos/id2
|
71
71
|
if number_of_arguments == 1
|
@@ -56,7 +56,7 @@ module ActionController
|
|
56
56
|
result = recognize_optimized(path, environment) and return result
|
57
57
|
|
58
58
|
# Route was not recognized. Try to find out why (maybe wrong verb).
|
59
|
-
allows = HTTP_METHODS.select { |verb| routes.find { |r| r.recognize(path, :method => verb) } }
|
59
|
+
allows = HTTP_METHODS.select { |verb| routes.find { |r| r.recognize(path, environment.merge(:method => verb)) } }
|
60
60
|
|
61
61
|
if environment[:method] && !HTTP_METHODS.include?(environment[:method])
|
62
62
|
raise NotImplemented.new(*allows)
|
@@ -98,7 +98,6 @@ module ActionController
|
|
98
98
|
if Array === item
|
99
99
|
i += 1
|
100
100
|
start = (i == 1)
|
101
|
-
final = (i == list.size)
|
102
101
|
tag, sub = item
|
103
102
|
if tag == :dynamic
|
104
103
|
body += padding + "#{start ? 'if' : 'elsif'} true\n"
|
@@ -35,6 +35,11 @@ module ActionController
|
|
35
35
|
segment.key if segment.respond_to? :key
|
36
36
|
end.compact
|
37
37
|
end
|
38
|
+
|
39
|
+
def required_segment_keys
|
40
|
+
required_segments = segments.select {|seg| (!seg.optional? && !seg.is_a?(DividerSegment)) || seg.is_a?(PathSegment) }
|
41
|
+
required_segments.collect { |seg| seg.key if seg.respond_to?(:key)}.compact
|
42
|
+
end
|
38
43
|
|
39
44
|
# Build a query string from the keys of the given hash. If +only_keys+
|
40
45
|
# is given (as an array), only the keys indicated will be used to build
|
@@ -122,6 +127,16 @@ module ActionController
|
|
122
127
|
super
|
123
128
|
end
|
124
129
|
|
130
|
+
def generate(options, hash, expire_on = {})
|
131
|
+
path, hash = generate_raw(options, hash, expire_on)
|
132
|
+
append_query_string(path, hash, extra_keys(options))
|
133
|
+
end
|
134
|
+
|
135
|
+
def generate_extras(options, hash, expire_on = {})
|
136
|
+
path, hash = generate_raw(options, hash, expire_on)
|
137
|
+
[path, extra_keys(options)]
|
138
|
+
end
|
139
|
+
|
125
140
|
private
|
126
141
|
def requirement_for(key)
|
127
142
|
return requirements[key] if requirements.key? key
|
@@ -150,11 +165,6 @@ module ActionController
|
|
150
165
|
# the query string. (Never use keys from the recalled request when building the
|
151
166
|
# query string.)
|
152
167
|
|
153
|
-
method_decl = "def generate(#{args})\npath, hash = generate_raw(options, hash, expire_on)\nappend_query_string(path, hash, extra_keys(options))\nend"
|
154
|
-
instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})"
|
155
|
-
|
156
|
-
method_decl = "def generate_extras(#{args})\npath, hash = generate_raw(options, hash, expire_on)\n[path, extra_keys(options)]\nend"
|
157
|
-
instance_eval method_decl, "generated code (#{__FILE__}:#{__LINE__})"
|
158
168
|
raw_method
|
159
169
|
end
|
160
170
|
|
@@ -7,6 +7,8 @@ module ActionController
|
|
7
7
|
# Mapper instances have relatively few instance methods, in order to avoid
|
8
8
|
# clashes with named routes.
|
9
9
|
class Mapper #:doc:
|
10
|
+
include ActionController::Resources
|
11
|
+
|
10
12
|
def initialize(set) #:nodoc:
|
11
13
|
@set = set
|
12
14
|
end
|
@@ -143,10 +145,10 @@ module ActionController
|
|
143
145
|
def define_hash_access(route, name, kind, options)
|
144
146
|
selector = hash_access_name(name, kind)
|
145
147
|
named_helper_module_eval <<-end_eval # We use module_eval to avoid leaks
|
146
|
-
def #{selector}(options = nil)
|
147
|
-
options ? #{options.inspect}.merge(options) : #{options.inspect}
|
148
|
-
end
|
149
|
-
protected :#{selector}
|
148
|
+
def #{selector}(options = nil) # def hash_for_users_url(options = nil)
|
149
|
+
options ? #{options.inspect}.merge(options) : #{options.inspect} # options ? {:only_path=>false}.merge(options) : {:only_path=>false}
|
150
|
+
end # end
|
151
|
+
protected :#{selector} # protected :hash_for_users_url
|
150
152
|
end_eval
|
151
153
|
helpers << selector
|
152
154
|
end
|
@@ -171,32 +173,43 @@ module ActionController
|
|
171
173
|
# foo_url(bar, baz, bang, :sort_by => 'baz')
|
172
174
|
#
|
173
175
|
named_helper_module_eval <<-end_eval # We use module_eval to avoid leaks
|
174
|
-
def #{selector}(*args)
|
175
|
-
|
176
|
-
#{generate_optimisation_block(route, kind)}
|
177
|
-
|
178
|
-
opts = if args.empty? || Hash === args.first
|
179
|
-
args.first || {}
|
180
|
-
else
|
181
|
-
options = args.extract_options!
|
182
|
-
args = args.zip(#{route.segment_keys.inspect}).inject({}) do |h, (v, k)|
|
183
|
-
h[k] = v
|
184
|
-
h
|
185
|
-
end
|
186
|
-
options.merge(args)
|
187
|
-
end
|
188
|
-
|
189
|
-
url_for(#{hash_access_method}(opts))
|
190
|
-
|
191
|
-
|
176
|
+
def #{selector}(*args) # def users_url(*args)
|
177
|
+
#
|
178
|
+
#{generate_optimisation_block(route, kind)} # #{generate_optimisation_block(route, kind)}
|
179
|
+
#
|
180
|
+
opts = if args.empty? || Hash === args.first # opts = if args.empty? || Hash === args.first
|
181
|
+
args.first || {} # args.first || {}
|
182
|
+
else # else
|
183
|
+
options = args.extract_options! # options = args.extract_options!
|
184
|
+
args = args.zip(#{route.segment_keys.inspect}).inject({}) do |h, (v, k)| # args = args.zip([]).inject({}) do |h, (v, k)|
|
185
|
+
h[k] = v # h[k] = v
|
186
|
+
h # h
|
187
|
+
end # end
|
188
|
+
options.merge(args) # options.merge(args)
|
189
|
+
end # end
|
190
|
+
#
|
191
|
+
url_for(#{hash_access_method}(opts)) # url_for(hash_for_users_url(opts))
|
192
|
+
#
|
193
|
+
end # end
|
194
|
+
#Add an alias to support the now deprecated formatted_* URL. # #Add an alias to support the now deprecated formatted_* URL.
|
195
|
+
def formatted_#{selector}(*args) # def formatted_users_url(*args)
|
196
|
+
ActiveSupport::Deprecation.warn( # ActiveSupport::Deprecation.warn(
|
197
|
+
"formatted_#{selector}() has been deprecated. " + # "formatted_users_url() has been deprecated. " +
|
198
|
+
"Please pass format to the standard " + # "Please pass format to the standard " +
|
199
|
+
"#{selector} method instead.", caller) # "users_url method instead.", caller)
|
200
|
+
#{selector}(*args) # users_url(*args)
|
201
|
+
end # end
|
202
|
+
protected :#{selector} # protected :users_url
|
192
203
|
end_eval
|
193
204
|
helpers << selector
|
194
205
|
end
|
195
206
|
end
|
196
207
|
|
197
|
-
attr_accessor :routes, :named_routes, :
|
208
|
+
attr_accessor :routes, :named_routes, :configuration_files
|
198
209
|
|
199
210
|
def initialize
|
211
|
+
self.configuration_files = []
|
212
|
+
|
200
213
|
self.routes = []
|
201
214
|
self.named_routes = NamedRouteCollection.new
|
202
215
|
|
@@ -210,7 +223,6 @@ module ActionController
|
|
210
223
|
end
|
211
224
|
|
212
225
|
def draw
|
213
|
-
clear!
|
214
226
|
yield Mapper.new(self)
|
215
227
|
install_helpers
|
216
228
|
end
|
@@ -234,8 +246,22 @@ module ActionController
|
|
234
246
|
routes.empty?
|
235
247
|
end
|
236
248
|
|
249
|
+
def add_configuration_file(path)
|
250
|
+
self.configuration_files << path
|
251
|
+
end
|
252
|
+
|
253
|
+
# Deprecated accessor
|
254
|
+
def configuration_file=(path)
|
255
|
+
add_configuration_file(path)
|
256
|
+
end
|
257
|
+
|
258
|
+
# Deprecated accessor
|
259
|
+
def configuration_file
|
260
|
+
configuration_files
|
261
|
+
end
|
262
|
+
|
237
263
|
def load!
|
238
|
-
Routing.use_controllers!
|
264
|
+
Routing.use_controllers!(nil) # Clear the controller cache so we may discover new ones
|
239
265
|
clear!
|
240
266
|
load_routes!
|
241
267
|
end
|
@@ -244,24 +270,39 @@ module ActionController
|
|
244
270
|
alias reload! load!
|
245
271
|
|
246
272
|
def reload
|
247
|
-
if
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
273
|
+
if configuration_files.any? && @routes_last_modified
|
274
|
+
if routes_changed_at == @routes_last_modified
|
275
|
+
return # routes didn't change, don't reload
|
276
|
+
else
|
277
|
+
@routes_last_modified = routes_changed_at
|
278
|
+
end
|
253
279
|
end
|
280
|
+
|
254
281
|
load!
|
255
282
|
end
|
256
283
|
|
257
284
|
def load_routes!
|
258
|
-
if
|
259
|
-
load
|
260
|
-
@routes_last_modified =
|
285
|
+
if configuration_files.any?
|
286
|
+
configuration_files.each { |config| load(config) }
|
287
|
+
@routes_last_modified = routes_changed_at
|
261
288
|
else
|
262
289
|
add_route ":controller/:action/:id"
|
263
290
|
end
|
264
291
|
end
|
292
|
+
|
293
|
+
def routes_changed_at
|
294
|
+
routes_changed_at = nil
|
295
|
+
|
296
|
+
configuration_files.each do |config|
|
297
|
+
config_changed_at = File.stat(config).mtime
|
298
|
+
|
299
|
+
if routes_changed_at.nil? || config_changed_at > routes_changed_at
|
300
|
+
routes_changed_at = config_changed_at
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
routes_changed_at
|
305
|
+
end
|
265
306
|
|
266
307
|
def add_route(path, options = {})
|
267
308
|
route = builder.build(path, options)
|
@@ -363,7 +404,7 @@ module ActionController
|
|
363
404
|
end
|
364
405
|
|
365
406
|
# don't use the recalled keys when determining which routes to check
|
366
|
-
routes = routes_by_controller[controller][action][options.keys.sort_by { |x| x.object_id }]
|
407
|
+
routes = routes_by_controller[controller][action][options.reject {|k,v| !v}.keys.sort_by { |x| x.object_id }]
|
367
408
|
|
368
409
|
routes.each do |route|
|
369
410
|
results = route.__send__(method, options, merged, expire_on)
|
@@ -386,6 +427,12 @@ module ActionController
|
|
386
427
|
end
|
387
428
|
end
|
388
429
|
|
430
|
+
def call(env)
|
431
|
+
request = Request.new(env)
|
432
|
+
app = Routing::Routes.recognize(request)
|
433
|
+
app.call(env).to_a
|
434
|
+
end
|
435
|
+
|
389
436
|
def recognize(request)
|
390
437
|
params = recognize_path(request.path, extract_request_environment(request))
|
391
438
|
request.path_parameters = params.with_indifferent_access
|
@@ -304,5 +304,40 @@ module ActionController
|
|
304
304
|
end
|
305
305
|
end
|
306
306
|
end
|
307
|
+
|
308
|
+
# The OptionalFormatSegment allows for any resource route to have an optional
|
309
|
+
# :format, which decreases the amount of routes created by 50%.
|
310
|
+
class OptionalFormatSegment < DynamicSegment
|
311
|
+
|
312
|
+
def initialize(key = nil, options = {})
|
313
|
+
super(:format, {:optional => true}.merge(options))
|
314
|
+
end
|
315
|
+
|
316
|
+
def interpolation_chunk
|
317
|
+
"." + super
|
318
|
+
end
|
319
|
+
|
320
|
+
def regexp_chunk
|
321
|
+
'/|(\.[^/?\.]+)?'
|
322
|
+
end
|
323
|
+
|
324
|
+
def to_s
|
325
|
+
'(.:format)?'
|
326
|
+
end
|
327
|
+
|
328
|
+
def extract_value
|
329
|
+
"#{local_name} = options[:#{key}] && options[:#{key}].to_s.downcase"
|
330
|
+
end
|
331
|
+
|
332
|
+
#the value should not include the period (.)
|
333
|
+
def match_extraction(next_capture)
|
334
|
+
%[
|
335
|
+
if (m = match[#{next_capture}])
|
336
|
+
params[:#{key}] = URI.unescape(m.from(1))
|
337
|
+
end
|
338
|
+
]
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
307
342
|
end
|
308
343
|
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
require 'rack/utils'
|
2
|
+
|
3
|
+
module ActionController
|
4
|
+
module Session
|
5
|
+
class AbstractStore
|
6
|
+
ENV_SESSION_KEY = 'rack.session'.freeze
|
7
|
+
ENV_SESSION_OPTIONS_KEY = 'rack.session.options'.freeze
|
8
|
+
|
9
|
+
HTTP_COOKIE = 'HTTP_COOKIE'.freeze
|
10
|
+
SET_COOKIE = 'Set-Cookie'.freeze
|
11
|
+
|
12
|
+
class SessionHash < Hash
|
13
|
+
def initialize(by, env)
|
14
|
+
super()
|
15
|
+
@by = by
|
16
|
+
@env = env
|
17
|
+
@loaded = false
|
18
|
+
end
|
19
|
+
|
20
|
+
def session_id
|
21
|
+
ActiveSupport::Deprecation.warn(
|
22
|
+
"ActionController::Session::AbstractStore::SessionHash#session_id " +
|
23
|
+
"has been deprecated. Please use request.session_options[:id] instead.", caller)
|
24
|
+
@env[ENV_SESSION_OPTIONS_KEY][:id]
|
25
|
+
end
|
26
|
+
|
27
|
+
def [](key)
|
28
|
+
load! unless @loaded
|
29
|
+
super
|
30
|
+
end
|
31
|
+
|
32
|
+
def []=(key, value)
|
33
|
+
load! unless @loaded
|
34
|
+
super
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_hash
|
38
|
+
h = {}.replace(self)
|
39
|
+
h.delete_if { |k,v| v.nil? }
|
40
|
+
h
|
41
|
+
end
|
42
|
+
|
43
|
+
def data
|
44
|
+
ActiveSupport::Deprecation.warn(
|
45
|
+
"ActionController::Session::AbstractStore::SessionHash#data " +
|
46
|
+
"has been deprecated. Please use #to_hash instead.", caller)
|
47
|
+
to_hash
|
48
|
+
end
|
49
|
+
|
50
|
+
def inspect
|
51
|
+
load! unless @loaded
|
52
|
+
super
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
def loaded?
|
57
|
+
@loaded
|
58
|
+
end
|
59
|
+
|
60
|
+
def load!
|
61
|
+
stale_session_check! do
|
62
|
+
id, session = @by.send(:load_session, @env)
|
63
|
+
(@env[ENV_SESSION_OPTIONS_KEY] ||= {})[:id] = id
|
64
|
+
replace(session)
|
65
|
+
@loaded = true
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def stale_session_check!
|
70
|
+
yield
|
71
|
+
rescue ArgumentError => argument_error
|
72
|
+
if argument_error.message =~ %r{undefined class/module ([\w:]*\w)}
|
73
|
+
begin
|
74
|
+
# Note that the regexp does not allow $1 to end with a ':'
|
75
|
+
$1.constantize
|
76
|
+
rescue LoadError, NameError => const_error
|
77
|
+
raise ActionController::SessionRestoreError, "Session contains objects whose class definition isn\\'t available.\nRemember to require the classes for all objects kept in the session.\n(Original exception: \#{const_error.message} [\#{const_error.class}])\n"
|
78
|
+
end
|
79
|
+
|
80
|
+
retry
|
81
|
+
else
|
82
|
+
raise
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
DEFAULT_OPTIONS = {
|
88
|
+
:key => '_session_id',
|
89
|
+
:path => '/',
|
90
|
+
:domain => nil,
|
91
|
+
:expire_after => nil,
|
92
|
+
:secure => false,
|
93
|
+
:httponly => true,
|
94
|
+
:cookie_only => true
|
95
|
+
}
|
96
|
+
|
97
|
+
def initialize(app, options = {})
|
98
|
+
# Process legacy CGI options
|
99
|
+
options = options.symbolize_keys
|
100
|
+
if options.has_key?(:session_path)
|
101
|
+
options[:path] = options.delete(:session_path)
|
102
|
+
end
|
103
|
+
if options.has_key?(:session_key)
|
104
|
+
options[:key] = options.delete(:session_key)
|
105
|
+
end
|
106
|
+
if options.has_key?(:session_http_only)
|
107
|
+
options[:httponly] = options.delete(:session_http_only)
|
108
|
+
end
|
109
|
+
|
110
|
+
@app = app
|
111
|
+
@default_options = DEFAULT_OPTIONS.merge(options)
|
112
|
+
@key = @default_options[:key]
|
113
|
+
@cookie_only = @default_options[:cookie_only]
|
114
|
+
end
|
115
|
+
|
116
|
+
def call(env)
|
117
|
+
session = SessionHash.new(self, env)
|
118
|
+
|
119
|
+
env[ENV_SESSION_KEY] = session
|
120
|
+
env[ENV_SESSION_OPTIONS_KEY] = @default_options.dup
|
121
|
+
|
122
|
+
response = @app.call(env)
|
123
|
+
|
124
|
+
session_data = env[ENV_SESSION_KEY]
|
125
|
+
options = env[ENV_SESSION_OPTIONS_KEY]
|
126
|
+
|
127
|
+
if !session_data.is_a?(AbstractStore::SessionHash) || session_data.send(:loaded?) || options[:expire_after]
|
128
|
+
session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.send(:loaded?)
|
129
|
+
|
130
|
+
sid = options[:id] || generate_sid
|
131
|
+
|
132
|
+
unless set_session(env, sid, session_data.to_hash)
|
133
|
+
return response
|
134
|
+
end
|
135
|
+
|
136
|
+
cookie = Rack::Utils.escape(@key) + '=' + Rack::Utils.escape(sid)
|
137
|
+
cookie << "; domain=#{options[:domain]}" if options[:domain]
|
138
|
+
cookie << "; path=#{options[:path]}" if options[:path]
|
139
|
+
if options[:expire_after]
|
140
|
+
expiry = Time.now + options[:expire_after]
|
141
|
+
cookie << "; expires=#{expiry.httpdate}"
|
142
|
+
end
|
143
|
+
cookie << "; Secure" if options[:secure]
|
144
|
+
cookie << "; HttpOnly" if options[:httponly]
|
145
|
+
|
146
|
+
headers = response[1]
|
147
|
+
unless headers[SET_COOKIE].blank?
|
148
|
+
headers[SET_COOKIE] << "\n#{cookie}"
|
149
|
+
else
|
150
|
+
headers[SET_COOKIE] = cookie
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
response
|
155
|
+
end
|
156
|
+
|
157
|
+
private
|
158
|
+
def generate_sid
|
159
|
+
ActiveSupport::SecureRandom.hex(16)
|
160
|
+
end
|
161
|
+
|
162
|
+
def load_session(env)
|
163
|
+
request = Rack::Request.new(env)
|
164
|
+
sid = request.cookies[@key]
|
165
|
+
unless @cookie_only
|
166
|
+
sid ||= request.params[@key]
|
167
|
+
end
|
168
|
+
sid, session = get_session(env, sid)
|
169
|
+
[sid, session]
|
170
|
+
end
|
171
|
+
|
172
|
+
def get_session(env, sid)
|
173
|
+
raise '#get_session needs to be implemented.'
|
174
|
+
end
|
175
|
+
|
176
|
+
def set_session(env, sid, session_data)
|
177
|
+
raise '#set_session needs to be implemented.'
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|