actionpack 3.1.12 → 3.2.0.rc1
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.md +5503 -108
- data/README.rdoc +3 -3
- data/lib/abstract_controller/asset_paths.rb +1 -1
- data/lib/abstract_controller/base.rb +1 -1
- data/lib/abstract_controller/callbacks.rb +102 -18
- data/lib/abstract_controller/helpers.rb +1 -1
- data/lib/abstract_controller/layouts.rb +116 -50
- data/lib/abstract_controller/logger.rb +1 -1
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -2
- data/lib/abstract_controller/rendering.rb +1 -6
- data/lib/abstract_controller/view_paths.rb +6 -5
- data/lib/action_controller.rb +0 -15
- data/lib/action_controller/caching.rb +0 -1
- data/lib/action_controller/caching/actions.rb +5 -6
- data/lib/action_controller/caching/fragments.rb +18 -18
- data/lib/action_controller/caching/pages.rb +7 -6
- data/lib/action_controller/caching/sweeping.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +8 -4
- data/lib/action_controller/metal.rb +7 -1
- data/lib/action_controller/metal/conditional_get.rb +49 -4
- data/lib/action_controller/metal/data_streaming.rb +17 -5
- data/lib/action_controller/metal/force_ssl.rb +8 -5
- data/lib/action_controller/metal/helpers.rb +7 -4
- data/lib/action_controller/metal/http_authentication.rb +9 -12
- data/lib/action_controller/metal/instrumentation.rb +9 -4
- data/lib/action_controller/metal/mime_responds.rb +4 -4
- data/lib/action_controller/metal/params_wrapper.rb +12 -8
- data/lib/action_controller/metal/redirecting.rb +7 -6
- data/lib/action_controller/metal/renderers.rb +9 -11
- data/lib/action_controller/metal/request_forgery_protection.rb +2 -1
- data/lib/action_controller/metal/rescue.rb +13 -0
- data/lib/action_controller/metal/responder.rb +11 -23
- data/lib/action_controller/metal/streaming.rb +0 -25
- data/lib/action_controller/railtie.rb +1 -0
- data/lib/action_controller/railties/paths.rb +4 -3
- data/lib/action_controller/record_identifier.rb +4 -4
- data/lib/action_controller/test_case.rb +60 -56
- data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +6 -6
- data/lib/action_dispatch.rb +5 -1
- data/lib/action_dispatch/http/cache.rb +27 -15
- data/lib/action_dispatch/http/filter_parameters.rb +3 -1
- data/lib/action_dispatch/http/headers.rb +3 -5
- data/lib/action_dispatch/http/mime_negotiation.rb +2 -1
- data/lib/action_dispatch/http/mime_type.rb +7 -3
- data/lib/action_dispatch/http/mime_types.rb +12 -0
- data/lib/action_dispatch/http/parameter_filter.rb +3 -1
- data/lib/action_dispatch/http/parameters.rb +0 -4
- data/lib/action_dispatch/http/request.rb +18 -68
- data/lib/action_dispatch/http/response.rb +11 -32
- data/lib/action_dispatch/http/upload.rb +3 -14
- data/lib/action_dispatch/http/url.rb +1 -1
- data/lib/action_dispatch/middleware/callbacks.rb +1 -2
- data/lib/action_dispatch/middleware/cookies.rb +20 -16
- data/lib/action_dispatch/middleware/debug_exceptions.rb +82 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +78 -0
- data/lib/action_dispatch/middleware/flash.rb +6 -9
- data/lib/action_dispatch/middleware/params_parser.rb +6 -11
- data/lib/action_dispatch/middleware/public_exceptions.rb +30 -0
- data/lib/action_dispatch/middleware/reloader.rb +38 -14
- data/lib/action_dispatch/middleware/remote_ip.rb +66 -36
- data/lib/action_dispatch/middleware/request_id.rb +39 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +4 -16
- data/lib/action_dispatch/middleware/session/cache_store.rb +50 -0
- data/lib/action_dispatch/middleware/session/cookie_store.rb +1 -1
- data/lib/action_dispatch/middleware/show_exceptions.rb +58 -142
- data/lib/action_dispatch/middleware/static.rb +2 -10
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +13 -8
- data/lib/action_dispatch/railtie.rb +15 -1
- data/lib/action_dispatch/routing.rb +1 -2
- data/lib/action_dispatch/routing/mapper.rb +108 -107
- data/lib/action_dispatch/routing/redirection.rb +63 -69
- data/lib/action_dispatch/routing/route_set.rb +75 -43
- data/lib/action_dispatch/routing/routes_proxy.rb +0 -4
- data/lib/action_dispatch/routing/url_for.rb +3 -3
- data/lib/action_dispatch/testing/assertions/response.rb +5 -7
- data/lib/action_dispatch/testing/assertions/routing.rb +10 -9
- data/lib/action_dispatch/testing/integration.rb +8 -25
- data/lib/action_dispatch/testing/test_process.rb +3 -2
- data/lib/action_dispatch/testing/test_request.rb +4 -23
- data/lib/action_pack/version.rb +3 -3
- data/lib/action_view.rb +1 -5
- data/lib/action_view/asset_paths.rb +7 -8
- data/lib/action_view/base.rb +7 -5
- data/lib/action_view/helpers/asset_paths.rb +1 -1
- data/lib/action_view/helpers/asset_tag_helper.rb +4 -8
- data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +3 -0
- data/lib/action_view/helpers/atom_feed_helper.rb +2 -2
- data/lib/action_view/helpers/capture_helper.rb +3 -3
- data/lib/action_view/helpers/controller_helper.rb +1 -1
- data/lib/action_view/helpers/date_helper.rb +26 -18
- data/lib/action_view/helpers/debug_helper.rb +1 -1
- data/lib/action_view/helpers/form_helper.rb +71 -13
- data/lib/action_view/helpers/form_options_helper.rb +65 -34
- data/lib/action_view/helpers/form_tag_helper.rb +24 -18
- data/lib/action_view/helpers/javascript_helper.rb +12 -3
- data/lib/action_view/helpers/number_helper.rb +3 -2
- data/lib/action_view/helpers/record_tag_helper.rb +51 -5
- data/lib/action_view/helpers/rendering_helper.rb +2 -2
- data/lib/action_view/helpers/sanitize_helper.rb +6 -7
- data/lib/action_view/helpers/tag_helper.rb +1 -1
- data/lib/action_view/helpers/text_helper.rb +5 -4
- data/lib/action_view/helpers/url_helper.rb +19 -11
- data/lib/action_view/locale/en.yml +6 -0
- data/lib/action_view/log_subscriber.rb +1 -1
- data/lib/action_view/lookup_context.rb +123 -125
- data/lib/action_view/path_set.rb +60 -13
- data/lib/action_view/renderer/abstract_renderer.rb +16 -11
- data/lib/action_view/renderer/partial_renderer.rb +59 -40
- data/lib/action_view/renderer/template_renderer.rb +29 -17
- data/lib/action_view/template.rb +0 -1
- data/lib/action_view/template/error.rb +6 -5
- data/lib/action_view/template/handlers.rb +0 -6
- data/lib/action_view/template/handlers/builder.rb +10 -1
- data/lib/action_view/template/handlers/erb.rb +2 -2
- data/lib/action_view/template/resolver.rb +20 -31
- data/lib/action_view/test_case.rb +7 -10
- data/lib/sprockets/assets.rake +1 -1
- data/lib/sprockets/bootstrap.rb +3 -31
- data/lib/sprockets/compressors.rb +69 -7
- data/lib/sprockets/helpers/rails_helper.rb +6 -11
- data/lib/sprockets/railtie.rb +1 -0
- data/lib/sprockets/static_compiler.rb +0 -3
- metadata +57 -86
- checksums.yaml +0 -7
- data/lib/action_dispatch/middleware/closed_error.rb +0 -7
- data/lib/action_dispatch/routing/route.rb +0 -67
- data/lib/action_view/template/handler.rb +0 -49
@@ -5,8 +5,8 @@ module AbstractController
|
|
5
5
|
Module.new do
|
6
6
|
define_method(:inherited) do |klass|
|
7
7
|
super(klass)
|
8
|
-
if namespace = klass.parents.detect {|m| m.respond_to?(:
|
9
|
-
klass.send(:include, namespace.
|
8
|
+
if namespace = klass.parents.detect { |m| m.respond_to?(:railtie_routes_url_helpers) }
|
9
|
+
klass.send(:include, namespace.railtie_routes_url_helpers)
|
10
10
|
else
|
11
11
|
klass.send(:include, routes.url_helpers)
|
12
12
|
end
|
@@ -66,12 +66,7 @@ module AbstractController
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def view_context_class
|
69
|
-
@_view_context_class
|
70
|
-
end
|
71
|
-
|
72
|
-
def initialize(*)
|
73
|
-
@_view_context_class = nil
|
74
|
-
super
|
69
|
+
@_view_context_class ||= self.class.view_context_class
|
75
70
|
end
|
76
71
|
|
77
72
|
# An instance of a view class. The default view class is ActionView::Base
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'action_view/base'
|
2
|
+
|
1
3
|
module AbstractController
|
2
4
|
module ViewPaths
|
3
5
|
extend ActiveSupport::Concern
|
@@ -8,7 +10,7 @@ module AbstractController
|
|
8
10
|
self._view_paths.freeze
|
9
11
|
end
|
10
12
|
|
11
|
-
delegate :
|
13
|
+
delegate :template_exists?, :view_paths, :formats, :formats=,
|
12
14
|
:locale, :locale=, :to => :lookup_context
|
13
15
|
|
14
16
|
module ClassMethods
|
@@ -63,7 +65,7 @@ module AbstractController
|
|
63
65
|
# the default view path. You may also provide a custom view path
|
64
66
|
# (see ActionView::PathSet for more information)
|
65
67
|
def append_view_path(path)
|
66
|
-
self.
|
68
|
+
self._view_paths = view_paths + Array(path)
|
67
69
|
end
|
68
70
|
|
69
71
|
# Prepend a path to the list of view paths for this controller.
|
@@ -73,7 +75,7 @@ module AbstractController
|
|
73
75
|
# the default view path. You may also provide a custom view path
|
74
76
|
# (see ActionView::PathSet for more information)
|
75
77
|
def prepend_view_path(path)
|
76
|
-
self.
|
78
|
+
self._view_paths = ActionView::PathSet.new(Array(path) + view_paths)
|
77
79
|
end
|
78
80
|
|
79
81
|
# A list of all of the default view paths for this controller.
|
@@ -87,8 +89,7 @@ module AbstractController
|
|
87
89
|
# * <tt>paths</tt> - If a PathSet is provided, use that;
|
88
90
|
# otherwise, process the parameter into a PathSet.
|
89
91
|
def view_paths=(paths)
|
90
|
-
self._view_paths = ActionView::
|
91
|
-
self._view_paths.freeze
|
92
|
+
self._view_paths = ActionView::PathSet.new(Array.wrap(paths))
|
92
93
|
end
|
93
94
|
end
|
94
95
|
end
|
data/lib/action_controller.rb
CHANGED
@@ -47,21 +47,6 @@ module ActionController
|
|
47
47
|
|
48
48
|
eager_autoload do
|
49
49
|
autoload :RecordIdentifier
|
50
|
-
|
51
|
-
# TODO: Don't autoload exceptions, setup explicit
|
52
|
-
# requires for files that need them
|
53
|
-
autoload_at "action_controller/metal/exceptions" do
|
54
|
-
autoload :ActionControllerError
|
55
|
-
autoload :RenderError
|
56
|
-
autoload :RoutingError
|
57
|
-
autoload :MethodNotAllowed
|
58
|
-
autoload :NotImplemented
|
59
|
-
autoload :UnknownController
|
60
|
-
autoload :MissingFile
|
61
|
-
autoload :RenderError
|
62
|
-
autoload :SessionOverflowError
|
63
|
-
autoload :UnknownHttpMethod
|
64
|
-
end
|
65
50
|
end
|
66
51
|
end
|
67
52
|
|
@@ -24,7 +24,6 @@ module ActionController #:nodoc:
|
|
24
24
|
#
|
25
25
|
# config.action_controller.cache_store = :memory_store
|
26
26
|
# config.action_controller.cache_store = :file_store, "/path/to/cache/directory"
|
27
|
-
# config.action_controller.cache_store = :drb_store, "druby://localhost:9192"
|
28
27
|
# config.action_controller.cache_store = :mem_cache_store, "localhost"
|
29
28
|
# config.action_controller.cache_store = :mem_cache_store, Memcached::Rails.new("localhost:11211")
|
30
29
|
# config.action_controller.cache_store = MyOwnStore.new("parameter")
|
@@ -38,9 +38,9 @@ module ActionController #:nodoc:
|
|
38
38
|
# <tt>:action => 'lists'</tt> is not the same as
|
39
39
|
# <tt>:action => 'list', :format => :xml</tt>.
|
40
40
|
#
|
41
|
-
# You can
|
42
|
-
# <tt>:cache_path</tt> option.
|
43
|
-
# <tt>ActionCachePath.path_for</tt>.
|
41
|
+
# You can modify the default action cache path by passing a
|
42
|
+
# <tt>:cache_path</tt> option. This will be passed directly to
|
43
|
+
# <tt>ActionCachePath.path_for</tt>. This is handy for actions with
|
44
44
|
# multiple possible routes that should be cached differently. If a
|
45
45
|
# block is given, it is called with the current controller instance.
|
46
46
|
#
|
@@ -116,9 +116,8 @@ module ActionController #:nodoc:
|
|
116
116
|
def expire_action(options = {})
|
117
117
|
return unless cache_configured?
|
118
118
|
|
119
|
-
|
120
|
-
|
121
|
-
actions.each {|action| expire_action(options.merge(:action => action)) }
|
119
|
+
if options.is_a?(Hash) && options[:action].is_a?(Array)
|
120
|
+
options[:action].each {|action| expire_action(options.merge(:action => action)) }
|
122
121
|
else
|
123
122
|
expire_fragment(ActionCachePath.new(self, options, false).path)
|
124
123
|
end
|
@@ -1,36 +1,36 @@
|
|
1
1
|
module ActionController #:nodoc:
|
2
2
|
module Caching
|
3
|
-
# Fragment caching is used for caching various blocks within
|
3
|
+
# Fragment caching is used for caching various blocks within
|
4
4
|
# views without caching the entire action as a whole. This is
|
5
|
-
# useful when certain elements of an action change frequently or
|
6
|
-
# depend on complicated state while other parts rarely change or
|
5
|
+
# useful when certain elements of an action change frequently or
|
6
|
+
# depend on complicated state while other parts rarely change or
|
7
7
|
# can be shared amongst multiple parties. The caching is done using
|
8
|
-
# the <tt>cache</tt> helper available in the Action View. A
|
8
|
+
# the <tt>cache</tt> helper available in the Action View. A
|
9
9
|
# template with fragment caching might look like:
|
10
10
|
#
|
11
11
|
# <b>Hello <%= @name %></b>
|
12
12
|
#
|
13
13
|
# <% cache do %>
|
14
14
|
# All the topics in the system:
|
15
|
-
# <%= render :partial => "topic", :collection => Topic.
|
15
|
+
# <%= render :partial => "topic", :collection => Topic.all %>
|
16
16
|
# <% end %>
|
17
17
|
#
|
18
18
|
# This cache will bind the name of the action that called it, so if
|
19
|
-
# this code was part of the view for the topics/list action, you
|
19
|
+
# this code was part of the view for the topics/list action, you
|
20
20
|
# would be able to invalidate it using:
|
21
21
|
#
|
22
22
|
# expire_fragment(:controller => "topics", :action => "list")
|
23
23
|
#
|
24
|
-
# This default behavior is limited if you need to cache multiple
|
25
|
-
# fragments per action or if the action itself is cached using
|
26
|
-
# <tt>caches_action</tt>. To remedy this, there is an option to
|
27
|
-
# qualify the name of the cached fragment by using the
|
24
|
+
# This default behavior is limited if you need to cache multiple
|
25
|
+
# fragments per action or if the action itself is cached using
|
26
|
+
# <tt>caches_action</tt>. To remedy this, there is an option to
|
27
|
+
# qualify the name of the cached fragment by using the
|
28
28
|
# <tt>:action_suffix</tt> option:
|
29
29
|
#
|
30
30
|
# <% cache(:action => "list", :action_suffix => "all_topics") do %>
|
31
31
|
#
|
32
|
-
# That would result in a name such as
|
33
|
-
# <tt>/topics/list/all_topics</tt>, avoiding conflicts with the
|
32
|
+
# That would result in a name such as
|
33
|
+
# <tt>/topics/list/all_topics</tt>, avoiding conflicts with the
|
34
34
|
# action cache and with any fragments that use a different suffix.
|
35
35
|
# Note that the URL doesn't have to really exist or be callable
|
36
36
|
# - the url_for system is just used to generate unique cache names
|
@@ -38,21 +38,21 @@ module ActionController #:nodoc:
|
|
38
38
|
#
|
39
39
|
# The expiration call for this example is:
|
40
40
|
#
|
41
|
-
# expire_fragment(:controller => "topics",
|
42
|
-
# :action => "list",
|
41
|
+
# expire_fragment(:controller => "topics",
|
42
|
+
# :action => "list",
|
43
43
|
# :action_suffix => "all_topics")
|
44
44
|
module Fragments
|
45
45
|
# Given a key (as described in <tt>expire_fragment</tt>), returns
|
46
|
-
# a key suitable for use in reading, writing, or expiring a
|
46
|
+
# a key suitable for use in reading, writing, or expiring a
|
47
47
|
# cached fragment. If the key is a hash, the generated key is the
|
48
|
-
# return value of url_for on that hash (without the protocol).
|
48
|
+
# return value of url_for on that hash (without the protocol).
|
49
49
|
# All keys are prefixed with <tt>views/</tt> and uses
|
50
50
|
# ActiveSupport::Cache.expand_cache_key for the expansion.
|
51
51
|
def fragment_cache_key(key)
|
52
52
|
ActiveSupport::Cache.expand_cache_key(key.is_a?(Hash) ? url_for(key).split("://").last : key, :views)
|
53
53
|
end
|
54
54
|
|
55
|
-
# Writes <tt>content</tt> to the location signified by
|
55
|
+
# Writes <tt>content</tt> to the location signified by
|
56
56
|
# <tt>key</tt> (see <tt>expire_fragment</tt> for acceptable formats).
|
57
57
|
def write_fragment(key, content, options = nil)
|
58
58
|
return content unless cache_configured?
|
@@ -77,7 +77,7 @@ module ActionController #:nodoc:
|
|
77
77
|
end
|
78
78
|
end
|
79
79
|
|
80
|
-
# Check if a cached fragment from the location signified by
|
80
|
+
# Check if a cached fragment from the location signified by
|
81
81
|
# <tt>key</tt> exists (see <tt>expire_fragment</tt> for acceptable formats)
|
82
82
|
def fragment_exist?(key, options = nil)
|
83
83
|
return unless cache_configured?
|
@@ -16,9 +16,10 @@ module ActionController #:nodoc:
|
|
16
16
|
# caches_page :show, :new
|
17
17
|
# end
|
18
18
|
#
|
19
|
-
# This will generate cache files such as <tt>weblog/show/5.html</tt> and <tt>weblog/new.html</tt>,
|
20
|
-
#
|
21
|
-
#
|
19
|
+
# This will generate cache files such as <tt>weblog/show/5.html</tt> and <tt>weblog/new.html</tt>, which match the URLs used
|
20
|
+
# that would normally trigger dynamic page generation. Page caching works by configuring a web server to first check for the
|
21
|
+
# existence of files on disk, and to serve them directly when found, without passing the request through to Action Pack.
|
22
|
+
# This is much faster than handling the full dynamic request in the usual way.
|
22
23
|
#
|
23
24
|
# Expiration of the cache is handled by deleting the cached file, which results in a lazy regeneration approach where the cache
|
24
25
|
# is not restored before another hit is made against it. The API for doing so mimics the options from +url_for+ and friends:
|
@@ -121,7 +122,7 @@ module ActionController #:nodoc:
|
|
121
122
|
|
122
123
|
if options.is_a?(Hash)
|
123
124
|
if options[:action].is_a?(Array)
|
124
|
-
options[:action].
|
125
|
+
options[:action].each do |action|
|
125
126
|
self.class.expire_page(url_for(options.merge(:only_path => true, :action => action)))
|
126
127
|
end
|
127
128
|
else
|
@@ -132,8 +133,8 @@ module ActionController #:nodoc:
|
|
132
133
|
end
|
133
134
|
end
|
134
135
|
|
135
|
-
# Manually cache the +content+ in the key determined by +options+. If no content is provided, the contents of response.body is used
|
136
|
-
# If no options are provided, the
|
136
|
+
# Manually cache the +content+ in the key determined by +options+. If no content is provided, the contents of response.body is used.
|
137
|
+
# If no options are provided, the url of the current request being handled is used. Example:
|
137
138
|
# cache_page "I'm the cached content", :controller => "lists", :action => "show"
|
138
139
|
def cache_page(content = nil, options = nil)
|
139
140
|
return unless self.class.perform_caching && caching_allowed?
|
@@ -10,7 +10,7 @@ module ActionController
|
|
10
10
|
format = payload[:format]
|
11
11
|
format = format.to_s.upcase if format.is_a?(Symbol)
|
12
12
|
|
13
|
-
info "
|
13
|
+
info "Processing by #{payload[:controller]}##{payload[:action]} as #{format}"
|
14
14
|
info " Parameters: #{params.inspect}" unless params.empty?
|
15
15
|
end
|
16
16
|
|
@@ -20,14 +20,18 @@ module ActionController
|
|
20
20
|
|
21
21
|
status = payload[:status]
|
22
22
|
if status.nil? && payload[:exception].present?
|
23
|
-
status = Rack::Utils.status_code(ActionDispatch::
|
24
|
-
end
|
23
|
+
status = Rack::Utils.status_code(ActionDispatch::ExceptionWrapper.new({}, payload[:exception]).status_code)
|
24
|
+
end
|
25
25
|
message = "Completed #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]} in %.0fms" % event.duration
|
26
26
|
message << " (#{additions.join(" | ")})" unless additions.blank?
|
27
27
|
|
28
28
|
info(message)
|
29
29
|
end
|
30
30
|
|
31
|
+
def halted_callback(event)
|
32
|
+
info "Filter chain halted as #{event.payload[:filter]} rendered or redirected"
|
33
|
+
end
|
34
|
+
|
31
35
|
def send_file(event)
|
32
36
|
message = "Sent file %s"
|
33
37
|
message << " (%.1fms)"
|
@@ -59,4 +63,4 @@ module ActionController
|
|
59
63
|
end
|
60
64
|
end
|
61
65
|
|
62
|
-
ActionController::LogSubscriber.attach_to :action_controller
|
66
|
+
ActionController::LogSubscriber.attach_to :action_controller
|
@@ -182,7 +182,13 @@ module ActionController
|
|
182
182
|
end
|
183
183
|
|
184
184
|
def response_body=(val)
|
185
|
-
body =
|
185
|
+
body = if val.is_a?(String)
|
186
|
+
[val]
|
187
|
+
elsif val.nil? || val.respond_to?(:each)
|
188
|
+
val
|
189
|
+
else
|
190
|
+
[val]
|
191
|
+
end
|
186
192
|
super body
|
187
193
|
end
|
188
194
|
|
@@ -23,8 +23,27 @@ module ActionController
|
|
23
23
|
# This will render the show template if the request isn't sending a matching etag or
|
24
24
|
# If-Modified-Since header and just a <tt>304 Not Modified</tt> response if there's a match.
|
25
25
|
#
|
26
|
-
|
27
|
-
|
26
|
+
# You can also just pass a record where last_modified will be set by calling updated_at and the etag by passing the object itself. Example:
|
27
|
+
#
|
28
|
+
# def show
|
29
|
+
# @article = Article.find(params[:id])
|
30
|
+
# fresh_when(@article)
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# When passing a record, you can still set whether the public header:
|
34
|
+
#
|
35
|
+
# def show
|
36
|
+
# @article = Article.find(params[:id])
|
37
|
+
# fresh_when(@article, :public => true)
|
38
|
+
# end
|
39
|
+
def fresh_when(record_or_options, additional_options = {})
|
40
|
+
if record_or_options.is_a? Hash
|
41
|
+
options = record_or_options
|
42
|
+
options.assert_valid_keys(:etag, :last_modified, :public)
|
43
|
+
else
|
44
|
+
record = record_or_options
|
45
|
+
options = { :etag => record, :last_modified => record.try(:updated_at) }.merge(additional_options)
|
46
|
+
end
|
28
47
|
|
29
48
|
response.etag = options[:etag] if options[:etag]
|
30
49
|
response.last_modified = options[:last_modified] if options[:last_modified]
|
@@ -55,8 +74,34 @@ module ActionController
|
|
55
74
|
# end
|
56
75
|
# end
|
57
76
|
# end
|
58
|
-
|
59
|
-
|
77
|
+
#
|
78
|
+
# You can also just pass a record where last_modified will be set by calling updated_at and the etag by passing the object itself. Example:
|
79
|
+
#
|
80
|
+
# def show
|
81
|
+
# @article = Article.find(params[:id])
|
82
|
+
#
|
83
|
+
# if stale?(@article)
|
84
|
+
# @statistics = @article.really_expensive_call
|
85
|
+
# respond_to do |format|
|
86
|
+
# # all the supported formats
|
87
|
+
# end
|
88
|
+
# end
|
89
|
+
# end
|
90
|
+
#
|
91
|
+
# When passing a record, you can still set whether the public header:
|
92
|
+
#
|
93
|
+
# def show
|
94
|
+
# @article = Article.find(params[:id])
|
95
|
+
#
|
96
|
+
# if stale?(@article, :public => true)
|
97
|
+
# @statistics = @article.really_expensive_call
|
98
|
+
# respond_to do |format|
|
99
|
+
# # all the supported formats
|
100
|
+
# end
|
101
|
+
# end
|
102
|
+
# end
|
103
|
+
def stale?(record_or_options, additional_options = {})
|
104
|
+
fresh_when(record_or_options, additional_options)
|
60
105
|
!request.fresh?(response)
|
61
106
|
end
|
62
107
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'active_support/core_ext/file/path'
|
2
|
+
require 'action_controller/metal/exceptions'
|
2
3
|
|
3
4
|
module ActionController #:nodoc:
|
4
5
|
# Methods for sending arbitrary data and for streaming files to the browser,
|
@@ -26,8 +27,11 @@ module ActionController #:nodoc:
|
|
26
27
|
# Options:
|
27
28
|
# * <tt>:filename</tt> - suggests a filename for the browser to use.
|
28
29
|
# Defaults to <tt>File.basename(path)</tt>.
|
29
|
-
# * <tt>:type</tt> - specifies an HTTP content type.
|
30
|
-
# either a string or a symbol for a registered type register with
|
30
|
+
# * <tt>:type</tt> - specifies an HTTP content type.
|
31
|
+
# You can specify either a string or a symbol for a registered type register with
|
32
|
+
# <tt>Mime::Type.register</tt>, for example :json
|
33
|
+
# If omitted, type will be guessed from the file extension specified in <tt>:filename</tt>.
|
34
|
+
# If no content type is registered for the extension, default type 'application/octet-stream' will be used.
|
31
35
|
# * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
|
32
36
|
# Valid values are 'inline' and 'attachment' (default).
|
33
37
|
# * <tt>:status</tt> - specifies the status code to send with the response. Defaults to 200.
|
@@ -37,7 +41,7 @@ module ActionController #:nodoc:
|
|
37
41
|
#
|
38
42
|
# The default Content-Type and Content-Disposition headers are
|
39
43
|
# set to download arbitrary binary files in as many browsers as
|
40
|
-
# possible.
|
44
|
+
# possible. IE versions 4, 5, 5.5, and 6 are all known to have
|
41
45
|
# a variety of quirks (especially when downloading over SSL).
|
42
46
|
#
|
43
47
|
# Simple download:
|
@@ -58,8 +62,8 @@ module ActionController #:nodoc:
|
|
58
62
|
#
|
59
63
|
# Also be aware that the document may be cached by proxies and browsers.
|
60
64
|
# The Pragma and Cache-Control headers declare how the file may be cached
|
61
|
-
# by intermediaries.
|
62
|
-
# the server before releasing cached responses.
|
65
|
+
# by intermediaries. They default to require clients to validate with
|
66
|
+
# the server before releasing cached responses. See
|
63
67
|
# http://www.mnot.net/cache_docs/ for an overview of web caching and
|
64
68
|
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
|
65
69
|
# for the Cache-Control header spec.
|
@@ -84,6 +88,8 @@ module ActionController #:nodoc:
|
|
84
88
|
# * <tt>:filename</tt> - suggests a filename for the browser to use.
|
85
89
|
# * <tt>:type</tt> - specifies an HTTP content type. Defaults to 'application/octet-stream'. You can specify
|
86
90
|
# either a string or a symbol for a registered type register with <tt>Mime::Type.register</tt>, for example :json
|
91
|
+
# If omitted, type will be guessed from the file extension specified in <tt>:filename</tt>.
|
92
|
+
# If no content type is registered for the extension, default type 'application/octet-stream' will be used.
|
87
93
|
# * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
|
88
94
|
# Valid values are 'inline' and 'attachment' (default).
|
89
95
|
# * <tt>:status</tt> - specifies the status code to send with the response. Defaults to 200.
|
@@ -108,6 +114,8 @@ module ActionController #:nodoc:
|
|
108
114
|
|
109
115
|
private
|
110
116
|
def send_file_headers!(options)
|
117
|
+
type_provided = options.has_key?(:type)
|
118
|
+
|
111
119
|
options.update(DEFAULT_SEND_FILE_OPTIONS.merge(options))
|
112
120
|
[:type, :disposition].each do |arg|
|
113
121
|
raise ArgumentError, ":#{arg} option required" if options[arg].nil?
|
@@ -123,6 +131,10 @@ module ActionController #:nodoc:
|
|
123
131
|
raise ArgumentError, "Unknown MIME type #{options[:type]}" unless extension
|
124
132
|
self.content_type = extension
|
125
133
|
else
|
134
|
+
if !type_provided && options[:filename]
|
135
|
+
# If type wasn't provided, try guessing from file extension.
|
136
|
+
content_type = Mime::Type.lookup_by_extension(File.extname(options[:filename]).downcase.tr('.','')) || content_type
|
137
|
+
end
|
126
138
|
self.content_type = content_type
|
127
139
|
end
|
128
140
|
|
@@ -1,12 +1,12 @@
|
|
1
1
|
module ActionController
|
2
|
-
# This module provides a method which will
|
2
|
+
# This module provides a method which will redirect browser to use HTTPS
|
3
3
|
# protocol. This will ensure that user's sensitive information will be
|
4
4
|
# transferred safely over the internet. You _should_ always force browser
|
5
5
|
# to use HTTPS when you're transferring sensitive information such as
|
6
6
|
# user authentication, account information, or credit card information.
|
7
7
|
#
|
8
|
-
# Note that if you really
|
9
|
-
# consider using +config.force_ssl+ in your
|
8
|
+
# Note that if you are really concerned about your application security,
|
9
|
+
# you might consider using +config.force_ssl+ in your config file instead.
|
10
10
|
# That will ensure all the data transferred via HTTPS protocol and prevent
|
11
11
|
# user from getting session hijacked when accessing the site under unsecured
|
12
12
|
# HTTP protocol.
|
@@ -24,12 +24,15 @@ module ActionController
|
|
24
24
|
# * <tt>only</tt> - The callback should be run only for this action
|
25
25
|
# * <tt>except<tt> - The callback should be run for all actions except this action
|
26
26
|
def force_ssl(options = {})
|
27
|
+
host = options.delete(:host)
|
27
28
|
before_filter(options) do
|
28
29
|
if !request.ssl? && !Rails.env.development?
|
29
|
-
|
30
|
+
redirect_options = {:protocol => 'https://', :status => :moved_permanently}
|
31
|
+
redirect_options.merge!(:host => host) if host
|
32
|
+
redirect_to redirect_options
|
30
33
|
end
|
31
34
|
end
|
32
35
|
end
|
33
36
|
end
|
34
37
|
end
|
35
|
-
end
|
38
|
+
end
|