omg-actionpack 8.0.0.alpha1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +129 -0
- data/MIT-LICENSE +21 -0
- data/README.rdoc +57 -0
- data/lib/abstract_controller/asset_paths.rb +14 -0
- data/lib/abstract_controller/base.rb +299 -0
- data/lib/abstract_controller/caching/fragments.rb +149 -0
- data/lib/abstract_controller/caching.rb +68 -0
- data/lib/abstract_controller/callbacks.rb +265 -0
- data/lib/abstract_controller/collector.rb +44 -0
- data/lib/abstract_controller/deprecator.rb +9 -0
- data/lib/abstract_controller/error.rb +8 -0
- data/lib/abstract_controller/helpers.rb +243 -0
- data/lib/abstract_controller/logger.rb +16 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +25 -0
- data/lib/abstract_controller/rendering.rb +126 -0
- data/lib/abstract_controller/translation.rb +42 -0
- data/lib/abstract_controller/url_for.rb +37 -0
- data/lib/abstract_controller.rb +36 -0
- data/lib/action_controller/api/api_rendering.rb +18 -0
- data/lib/action_controller/api.rb +155 -0
- data/lib/action_controller/base.rb +332 -0
- data/lib/action_controller/caching.rb +49 -0
- data/lib/action_controller/deprecator.rb +9 -0
- data/lib/action_controller/form_builder.rb +55 -0
- data/lib/action_controller/log_subscriber.rb +96 -0
- data/lib/action_controller/metal/allow_browser.rb +123 -0
- data/lib/action_controller/metal/basic_implicit_render.rb +17 -0
- data/lib/action_controller/metal/conditional_get.rb +341 -0
- data/lib/action_controller/metal/content_security_policy.rb +86 -0
- data/lib/action_controller/metal/cookies.rb +20 -0
- data/lib/action_controller/metal/data_streaming.rb +154 -0
- data/lib/action_controller/metal/default_headers.rb +21 -0
- data/lib/action_controller/metal/etag_with_flash.rb +22 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +59 -0
- data/lib/action_controller/metal/exceptions.rb +106 -0
- data/lib/action_controller/metal/flash.rb +67 -0
- data/lib/action_controller/metal/head.rb +67 -0
- data/lib/action_controller/metal/helpers.rb +129 -0
- data/lib/action_controller/metal/http_authentication.rb +565 -0
- data/lib/action_controller/metal/implicit_render.rb +67 -0
- data/lib/action_controller/metal/instrumentation.rb +120 -0
- data/lib/action_controller/metal/live.rb +398 -0
- data/lib/action_controller/metal/logging.rb +22 -0
- data/lib/action_controller/metal/mime_responds.rb +337 -0
- data/lib/action_controller/metal/parameter_encoding.rb +84 -0
- data/lib/action_controller/metal/params_wrapper.rb +312 -0
- data/lib/action_controller/metal/permissions_policy.rb +38 -0
- data/lib/action_controller/metal/rate_limiting.rb +62 -0
- data/lib/action_controller/metal/redirecting.rb +251 -0
- data/lib/action_controller/metal/renderers.rb +181 -0
- data/lib/action_controller/metal/rendering.rb +260 -0
- data/lib/action_controller/metal/request_forgery_protection.rb +667 -0
- data/lib/action_controller/metal/rescue.rb +33 -0
- data/lib/action_controller/metal/streaming.rb +183 -0
- data/lib/action_controller/metal/strong_parameters.rb +1546 -0
- data/lib/action_controller/metal/testing.rb +25 -0
- data/lib/action_controller/metal/url_for.rb +65 -0
- data/lib/action_controller/metal.rb +339 -0
- data/lib/action_controller/railtie.rb +149 -0
- data/lib/action_controller/railties/helpers.rb +26 -0
- data/lib/action_controller/renderer.rb +161 -0
- data/lib/action_controller/template_assertions.rb +13 -0
- data/lib/action_controller/test_case.rb +691 -0
- data/lib/action_controller.rb +80 -0
- data/lib/action_dispatch/constants.rb +34 -0
- data/lib/action_dispatch/deprecator.rb +9 -0
- data/lib/action_dispatch/http/cache.rb +249 -0
- data/lib/action_dispatch/http/content_disposition.rb +47 -0
- data/lib/action_dispatch/http/content_security_policy.rb +365 -0
- data/lib/action_dispatch/http/filter_parameters.rb +80 -0
- data/lib/action_dispatch/http/filter_redirect.rb +50 -0
- data/lib/action_dispatch/http/headers.rb +134 -0
- data/lib/action_dispatch/http/mime_negotiation.rb +187 -0
- data/lib/action_dispatch/http/mime_type.rb +389 -0
- data/lib/action_dispatch/http/mime_types.rb +54 -0
- data/lib/action_dispatch/http/parameters.rb +119 -0
- data/lib/action_dispatch/http/permissions_policy.rb +189 -0
- data/lib/action_dispatch/http/rack_cache.rb +67 -0
- data/lib/action_dispatch/http/request.rb +498 -0
- data/lib/action_dispatch/http/response.rb +556 -0
- data/lib/action_dispatch/http/upload.rb +107 -0
- data/lib/action_dispatch/http/url.rb +344 -0
- data/lib/action_dispatch/journey/formatter.rb +226 -0
- data/lib/action_dispatch/journey/gtg/builder.rb +149 -0
- data/lib/action_dispatch/journey/gtg/simulator.rb +50 -0
- data/lib/action_dispatch/journey/gtg/transition_table.rb +217 -0
- data/lib/action_dispatch/journey/nfa/dot.rb +27 -0
- data/lib/action_dispatch/journey/nodes/node.rb +208 -0
- data/lib/action_dispatch/journey/parser.rb +103 -0
- data/lib/action_dispatch/journey/path/pattern.rb +209 -0
- data/lib/action_dispatch/journey/route.rb +189 -0
- data/lib/action_dispatch/journey/router/utils.rb +105 -0
- data/lib/action_dispatch/journey/router.rb +151 -0
- data/lib/action_dispatch/journey/routes.rb +82 -0
- data/lib/action_dispatch/journey/scanner.rb +70 -0
- data/lib/action_dispatch/journey/visitors.rb +267 -0
- data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
- data/lib/action_dispatch/journey/visualizer/fsm.js +159 -0
- data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
- data/lib/action_dispatch/journey.rb +7 -0
- data/lib/action_dispatch/log_subscriber.rb +25 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
- data/lib/action_dispatch/middleware/assume_ssl.rb +27 -0
- data/lib/action_dispatch/middleware/callbacks.rb +38 -0
- data/lib/action_dispatch/middleware/cookies.rb +719 -0
- data/lib/action_dispatch/middleware/debug_exceptions.rb +206 -0
- data/lib/action_dispatch/middleware/debug_locks.rb +129 -0
- data/lib/action_dispatch/middleware/debug_view.rb +73 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +350 -0
- data/lib/action_dispatch/middleware/executor.rb +32 -0
- data/lib/action_dispatch/middleware/flash.rb +318 -0
- data/lib/action_dispatch/middleware/host_authorization.rb +171 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +64 -0
- data/lib/action_dispatch/middleware/reloader.rb +16 -0
- data/lib/action_dispatch/middleware/remote_ip.rb +199 -0
- data/lib/action_dispatch/middleware/request_id.rb +50 -0
- data/lib/action_dispatch/middleware/server_timing.rb +78 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +112 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +66 -0
- data/lib/action_dispatch/middleware/session/cookie_store.rb +129 -0
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +34 -0
- data/lib/action_dispatch/middleware/show_exceptions.rb +88 -0
- data/lib/action_dispatch/middleware/ssl.rb +180 -0
- data/lib/action_dispatch/middleware/stack.rb +194 -0
- data/lib/action_dispatch/middleware/static.rb +192 -0
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +17 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +36 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +62 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +12 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +35 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +24 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +16 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +284 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +23 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +19 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +232 -0
- data/lib/action_dispatch/railtie.rb +77 -0
- data/lib/action_dispatch/request/session.rb +283 -0
- data/lib/action_dispatch/request/utils.rb +109 -0
- data/lib/action_dispatch/routing/endpoint.rb +19 -0
- data/lib/action_dispatch/routing/inspector.rb +323 -0
- data/lib/action_dispatch/routing/mapper.rb +2372 -0
- data/lib/action_dispatch/routing/polymorphic_routes.rb +363 -0
- data/lib/action_dispatch/routing/redirection.rb +218 -0
- data/lib/action_dispatch/routing/route_set.rb +958 -0
- data/lib/action_dispatch/routing/routes_proxy.rb +66 -0
- data/lib/action_dispatch/routing/url_for.rb +244 -0
- data/lib/action_dispatch/routing.rb +262 -0
- data/lib/action_dispatch/system_test_case.rb +206 -0
- data/lib/action_dispatch/system_testing/browser.rb +75 -0
- data/lib/action_dispatch/system_testing/driver.rb +85 -0
- data/lib/action_dispatch/system_testing/server.rb +33 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +164 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +23 -0
- data/lib/action_dispatch/testing/assertion_response.rb +48 -0
- data/lib/action_dispatch/testing/assertions/response.rb +114 -0
- data/lib/action_dispatch/testing/assertions/routing.rb +343 -0
- data/lib/action_dispatch/testing/assertions.rb +25 -0
- data/lib/action_dispatch/testing/integration.rb +694 -0
- data/lib/action_dispatch/testing/request_encoder.rb +60 -0
- data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
- data/lib/action_dispatch/testing/test_process.rb +57 -0
- data/lib/action_dispatch/testing/test_request.rb +73 -0
- data/lib/action_dispatch/testing/test_response.rb +58 -0
- data/lib/action_dispatch.rb +147 -0
- data/lib/action_pack/gem_version.rb +19 -0
- data/lib/action_pack/version.rb +12 -0
- data/lib/action_pack.rb +27 -0
- metadata +375 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d33d474bea49cdb46669b68c6760931543882ecf8e71a763115450ad027e8c6e
|
4
|
+
data.tar.gz: 411bc4578648aff7ce836bf341dbcac37c2b1430627c2b462b694a191913fc37
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 861232c9ddecbe87551fe6cf00b464cedba542bdb6c8be84be424ae3c082985ea1c84b8e5404b5d0be71137250582434df802774f1359e7626df1bdb415974df
|
7
|
+
data.tar.gz: c670f13c1bfc3a8ea58e3f7be5abbb986406d0c3f404bbe0f41c9f5dc01df2ccd301e1155f69d37dad4ff63648b4c108646b139cf70e9023c3593421702fdbe5
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
* Update `ActionController::Live` to use a thread-pool to reuse threads across requests.
|
2
|
+
|
3
|
+
*Adam Renberg Tamm*
|
4
|
+
|
5
|
+
* Introduce safer, more explicit params handling method with `params#expect` such that
|
6
|
+
`params.expect(table: [ :attr ])` replaces `params.require(:table).permit(:attr)`
|
7
|
+
|
8
|
+
Ensures params are filtered with consideration for the expected
|
9
|
+
types of values, improving handling of params and avoiding ignorable
|
10
|
+
errors caused by params tampering.
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
# If the url is altered to ?person=hacked
|
14
|
+
# Before
|
15
|
+
params.require(:person).permit(:name, :age, pets: [:name])
|
16
|
+
# raises NoMethodError, causing a 500 and potential error reporting
|
17
|
+
|
18
|
+
# After
|
19
|
+
params.expect(person: [ :name, :age, pets: [[:name]] ])
|
20
|
+
# raises ActionController::ParameterMissing, correctly returning a 400 error
|
21
|
+
```
|
22
|
+
|
23
|
+
You may also notice the new double array `[[:name]]`. In order to
|
24
|
+
declare when a param is expected to be an array of parameter hashes,
|
25
|
+
this new double array syntax is used to explicitly declare an array.
|
26
|
+
`expect` requires you to declare expected arrays in this way, and will
|
27
|
+
ignore arrays that are passed when, for example, `pet: [:name]` is used.
|
28
|
+
|
29
|
+
In order to preserve compatibility, `permit` does not adopt the new
|
30
|
+
double array syntax and is therefore more permissive about unexpected
|
31
|
+
types. Using `expect` everywhere is recommended.
|
32
|
+
|
33
|
+
We suggest replacing `params.require(:person).permit(:name, :age)`
|
34
|
+
with the direct replacement `params.expect(person: [:name, :age])`
|
35
|
+
to prevent external users from manipulating params to trigger 500
|
36
|
+
errors. A 400 error will be returned instead, using public/400.html
|
37
|
+
|
38
|
+
Usage of `params.require(:id)` should likewise be replaced with
|
39
|
+
`params.expect(:id)` which is designed to ensure that `params[:id]`
|
40
|
+
is a scalar and not an array or hash, also requiring the param.
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
# Before
|
44
|
+
User.find(params.require(:id)) # allows an array, altering behavior
|
45
|
+
|
46
|
+
# After
|
47
|
+
User.find(params.expect(:id)) # expect only returns non-blank permitted scalars (excludes Hash, Array, nil, "", etc)
|
48
|
+
```
|
49
|
+
|
50
|
+
*Martin Emde*
|
51
|
+
|
52
|
+
* System Testing: Disable Chrome's search engine choice by default in system tests.
|
53
|
+
|
54
|
+
*glaszig*
|
55
|
+
|
56
|
+
* Fix `Request#raw_post` raising `NoMethodError` when `rack.input` is `nil`.
|
57
|
+
|
58
|
+
*Hartley McGuire*
|
59
|
+
|
60
|
+
* Remove `racc` dependency by manually writing `ActionDispatch::Journey::Scanner`.
|
61
|
+
|
62
|
+
*Gannon McGibbon*
|
63
|
+
|
64
|
+
* Speed up `ActionDispatch::Routing::Mapper::Scope#[]` by merging frame hashes.
|
65
|
+
|
66
|
+
*Gannon McGibbon*
|
67
|
+
|
68
|
+
* Allow bots to ignore `allow_browser`.
|
69
|
+
|
70
|
+
*Matthew Nguyen*
|
71
|
+
|
72
|
+
* Deprecate drawing routes with multiple paths to make routing faster.
|
73
|
+
You may use `with_options` or a loop to make drawing multiple paths easier.
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
# Before
|
77
|
+
get "/users", "/other_path", to: "users#index"
|
78
|
+
|
79
|
+
# After
|
80
|
+
get "/users", to: "users#index"
|
81
|
+
get "/other_path", to: "users#index"
|
82
|
+
```
|
83
|
+
|
84
|
+
*Gannon McGibbon*
|
85
|
+
|
86
|
+
* Make `http_cache_forever` use `immutable: true`
|
87
|
+
|
88
|
+
*Nate Matykiewicz*
|
89
|
+
|
90
|
+
* Add `config.action_dispatch.strict_freshness`.
|
91
|
+
|
92
|
+
When set to `true`, the `ETag` header takes precedence over the `Last-Modified` header when both are present,
|
93
|
+
as specified by RFC 7232, Section 6.
|
94
|
+
|
95
|
+
Defaults to `false` to maintain compatibility with previous versions of Rails, but is enabled as part of
|
96
|
+
Rails 8.0 defaults.
|
97
|
+
|
98
|
+
*heka1024*
|
99
|
+
|
100
|
+
* Support `immutable` directive in Cache-Control
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
expires_in 1.minute, public: true, immutable: true
|
104
|
+
# Cache-Control: public, max-age=60, immutable
|
105
|
+
```
|
106
|
+
|
107
|
+
*heka1024*
|
108
|
+
|
109
|
+
* Add `:wasm_unsafe_eval` mapping for `content_security_policy`
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
# Before
|
113
|
+
policy.script_src "'wasm-unsafe-eval'"
|
114
|
+
|
115
|
+
# After
|
116
|
+
policy.script_src :wasm_unsafe_eval
|
117
|
+
```
|
118
|
+
|
119
|
+
*Joe Haig*
|
120
|
+
|
121
|
+
* Add `display_capture` and `keyboard_map` in `permissions_policy`
|
122
|
+
|
123
|
+
*Cyril Blaecke*
|
124
|
+
|
125
|
+
* Add `connect` route helper.
|
126
|
+
|
127
|
+
*Samuel Williams*
|
128
|
+
|
129
|
+
Please check [7-2-stable](https://github.com/rails/rails/blob/7-2-stable/actionpack/CHANGELOG.md) for previous changes.
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) David Heinemeier Hansson
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
data/README.rdoc
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
= Action Pack -- From request to response
|
2
|
+
|
3
|
+
Action Pack is a framework for handling and responding to web requests. It
|
4
|
+
provides mechanisms for *routing* (mapping request URLs to actions), defining
|
5
|
+
*controllers* that implement actions, and generating responses. In short, Action Pack
|
6
|
+
provides the controller layer in the MVC paradigm.
|
7
|
+
|
8
|
+
It consists of several modules:
|
9
|
+
|
10
|
+
* Action Dispatch, which parses information about the web request, handles
|
11
|
+
routing as defined by the user, and does advanced processing related to HTTP
|
12
|
+
such as MIME-type negotiation, decoding parameters in POST, PATCH, or PUT bodies,
|
13
|
+
handling HTTP caching logic, cookies and sessions.
|
14
|
+
|
15
|
+
* Action Controller, which provides a base controller class that can be
|
16
|
+
subclassed to implement filters and actions to handle requests. The result
|
17
|
+
of an action is typically content generated from views.
|
18
|
+
|
19
|
+
With the Ruby on \Rails framework, users only directly interface with the
|
20
|
+
Action Controller module. Necessary Action Dispatch functionality is activated
|
21
|
+
by default and Action View rendering is implicitly triggered by Action
|
22
|
+
Controller. However, these modules are designed to function on their own and
|
23
|
+
can be used outside of \Rails.
|
24
|
+
|
25
|
+
You can read more about Action Pack in the {Action Controller Overview}[https://guides.rubyonrails.org/action_controller_overview.html] guide.
|
26
|
+
|
27
|
+
== Download and installation
|
28
|
+
|
29
|
+
The latest version of Action Pack can be installed with RubyGems:
|
30
|
+
|
31
|
+
$ gem install actionpack
|
32
|
+
|
33
|
+
Source code can be downloaded as part of the \Rails project on GitHub:
|
34
|
+
|
35
|
+
* https://github.com/rails/rails/tree/main/actionpack
|
36
|
+
|
37
|
+
|
38
|
+
== License
|
39
|
+
|
40
|
+
Action Pack is released under the MIT license:
|
41
|
+
|
42
|
+
* https://opensource.org/licenses/MIT
|
43
|
+
|
44
|
+
|
45
|
+
== Support
|
46
|
+
|
47
|
+
API documentation is at:
|
48
|
+
|
49
|
+
* https://api.rubyonrails.org
|
50
|
+
|
51
|
+
Bug reports for the Ruby on \Rails project can be filed here:
|
52
|
+
|
53
|
+
* https://github.com/rails/rails/issues
|
54
|
+
|
55
|
+
Feature requests should be discussed on the rails-core mailing list here:
|
56
|
+
|
57
|
+
* https://discuss.rubyonrails.org/c/rubyonrails-core
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# :markup: markdown
|
4
|
+
|
5
|
+
module AbstractController
|
6
|
+
module AssetPaths # :nodoc:
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
config_accessor :asset_host, :assets_dir, :javascripts_dir,
|
11
|
+
:stylesheets_dir, :default_asset_host_protocol, :relative_url_root
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,299 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# :markup: markdown
|
4
|
+
|
5
|
+
require "abstract_controller/error"
|
6
|
+
require "active_support/configurable"
|
7
|
+
require "active_support/descendants_tracker"
|
8
|
+
require "active_support/core_ext/module/anonymous"
|
9
|
+
require "active_support/core_ext/module/attr_internal"
|
10
|
+
|
11
|
+
module AbstractController
|
12
|
+
# Raised when a non-existing controller action is triggered.
|
13
|
+
class ActionNotFound < StandardError
|
14
|
+
attr_reader :controller, :action # :nodoc:
|
15
|
+
|
16
|
+
def initialize(message = nil, controller = nil, action = nil) # :nodoc:
|
17
|
+
@controller = controller
|
18
|
+
@action = action
|
19
|
+
super(message)
|
20
|
+
end
|
21
|
+
|
22
|
+
if defined?(DidYouMean::Correctable) && defined?(DidYouMean::SpellChecker)
|
23
|
+
include DidYouMean::Correctable # :nodoc:
|
24
|
+
|
25
|
+
def corrections # :nodoc:
|
26
|
+
@corrections ||= DidYouMean::SpellChecker.new(dictionary: controller.class.action_methods).correct(action)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# # Abstract Controller Base
|
32
|
+
#
|
33
|
+
# AbstractController::Base is a low-level API. Nobody should be using it
|
34
|
+
# directly, and subclasses (like ActionController::Base) are expected to provide
|
35
|
+
# their own `render` method, since rendering means different things depending on
|
36
|
+
# the context.
|
37
|
+
class Base
|
38
|
+
##
|
39
|
+
# Returns the body of the HTTP response sent by the controller.
|
40
|
+
attr_internal :response_body
|
41
|
+
|
42
|
+
##
|
43
|
+
# Returns the name of the action this controller is processing.
|
44
|
+
attr_internal :action_name
|
45
|
+
|
46
|
+
##
|
47
|
+
# Returns the formats that can be processed by the controller.
|
48
|
+
attr_internal :formats
|
49
|
+
|
50
|
+
include ActiveSupport::Configurable
|
51
|
+
extend ActiveSupport::DescendantsTracker
|
52
|
+
|
53
|
+
class << self
|
54
|
+
attr_reader :abstract
|
55
|
+
alias_method :abstract?, :abstract
|
56
|
+
|
57
|
+
# Define a controller as abstract. See internal_methods for more details.
|
58
|
+
def abstract!
|
59
|
+
@abstract = true
|
60
|
+
end
|
61
|
+
|
62
|
+
def inherited(klass) # :nodoc:
|
63
|
+
# Define the abstract ivar on subclasses so that we don't get uninitialized ivar
|
64
|
+
# warnings
|
65
|
+
unless klass.instance_variable_defined?(:@abstract)
|
66
|
+
klass.instance_variable_set(:@abstract, false)
|
67
|
+
end
|
68
|
+
super
|
69
|
+
end
|
70
|
+
|
71
|
+
# A list of all internal methods for a controller. This finds the first abstract
|
72
|
+
# superclass of a controller, and gets a list of all public instance methods on
|
73
|
+
# that abstract class. Public instance methods of a controller would normally be
|
74
|
+
# considered action methods, so methods declared on abstract classes are being
|
75
|
+
# removed. (ActionController::Metal and ActionController::Base are defined as
|
76
|
+
# abstract)
|
77
|
+
def internal_methods
|
78
|
+
controller = self
|
79
|
+
methods = []
|
80
|
+
|
81
|
+
until controller.abstract?
|
82
|
+
methods += controller.public_instance_methods(false)
|
83
|
+
controller = controller.superclass
|
84
|
+
end
|
85
|
+
|
86
|
+
controller.public_instance_methods(true) - methods
|
87
|
+
end
|
88
|
+
|
89
|
+
# A list of method names that should be considered actions. This includes all
|
90
|
+
# public instance methods on a controller, less any internal methods (see
|
91
|
+
# internal_methods), adding back in any methods that are internal, but still
|
92
|
+
# exist on the class itself.
|
93
|
+
#
|
94
|
+
# #### Returns
|
95
|
+
# * `Set` - A set of all methods that should be considered actions.
|
96
|
+
#
|
97
|
+
def action_methods
|
98
|
+
@action_methods ||= begin
|
99
|
+
# All public instance methods of this class, including ancestors except for
|
100
|
+
# public instance methods of Base and its ancestors.
|
101
|
+
methods = public_instance_methods(true) - internal_methods
|
102
|
+
# Be sure to include shadowed public instance methods of this class.
|
103
|
+
methods.concat(public_instance_methods(false))
|
104
|
+
methods.map!(&:to_s)
|
105
|
+
methods.to_set
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# action_methods are cached and there is sometimes a need to refresh them.
|
110
|
+
# ::clear_action_methods! allows you to do that, so next time you run
|
111
|
+
# action_methods, they will be recalculated.
|
112
|
+
def clear_action_methods!
|
113
|
+
@action_methods = nil
|
114
|
+
end
|
115
|
+
|
116
|
+
# Returns the full controller name, underscored, without the ending Controller.
|
117
|
+
#
|
118
|
+
# class MyApp::MyPostsController < AbstractController::Base
|
119
|
+
#
|
120
|
+
# end
|
121
|
+
#
|
122
|
+
# MyApp::MyPostsController.controller_path # => "my_app/my_posts"
|
123
|
+
#
|
124
|
+
# #### Returns
|
125
|
+
# * `String`
|
126
|
+
#
|
127
|
+
def controller_path
|
128
|
+
@controller_path ||= name.delete_suffix("Controller").underscore unless anonymous?
|
129
|
+
end
|
130
|
+
|
131
|
+
# Refresh the cached action_methods when a new action_method is added.
|
132
|
+
def method_added(name)
|
133
|
+
super
|
134
|
+
clear_action_methods!
|
135
|
+
end
|
136
|
+
|
137
|
+
def eager_load! # :nodoc:
|
138
|
+
action_methods
|
139
|
+
nil
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
abstract!
|
144
|
+
|
145
|
+
# Calls the action going through the entire Action Dispatch stack.
|
146
|
+
#
|
147
|
+
# The actual method that is called is determined by calling #method_for_action.
|
148
|
+
# If no method can handle the action, then an AbstractController::ActionNotFound
|
149
|
+
# error is raised.
|
150
|
+
#
|
151
|
+
# #### Returns
|
152
|
+
# * `self`
|
153
|
+
#
|
154
|
+
def process(action, ...)
|
155
|
+
@_action_name = action.to_s
|
156
|
+
|
157
|
+
unless action_name = _find_action_name(@_action_name)
|
158
|
+
raise ActionNotFound.new("The action '#{action}' could not be found for #{self.class.name}", self, action)
|
159
|
+
end
|
160
|
+
|
161
|
+
@_response_body = nil
|
162
|
+
|
163
|
+
process_action(action_name, ...)
|
164
|
+
end
|
165
|
+
|
166
|
+
# Delegates to the class's ::controller_path.
|
167
|
+
def controller_path
|
168
|
+
self.class.controller_path
|
169
|
+
end
|
170
|
+
|
171
|
+
# Delegates to the class's ::action_methods.
|
172
|
+
def action_methods
|
173
|
+
self.class.action_methods
|
174
|
+
end
|
175
|
+
|
176
|
+
# Returns true if a method for the action is available and can be dispatched,
|
177
|
+
# false otherwise.
|
178
|
+
#
|
179
|
+
# Notice that `action_methods.include?("foo")` may return false and
|
180
|
+
# `available_action?("foo")` returns true because this method considers actions
|
181
|
+
# that are also available through other means, for example, implicit render
|
182
|
+
# ones.
|
183
|
+
#
|
184
|
+
# #### Parameters
|
185
|
+
# * `action_name` - The name of an action to be tested
|
186
|
+
#
|
187
|
+
def available_action?(action_name)
|
188
|
+
_find_action_name(action_name)
|
189
|
+
end
|
190
|
+
|
191
|
+
# Tests if a response body is set. Used to determine if the `process_action`
|
192
|
+
# callback needs to be terminated in AbstractController::Callbacks.
|
193
|
+
def performed?
|
194
|
+
response_body
|
195
|
+
end
|
196
|
+
|
197
|
+
# Returns true if the given controller is capable of rendering a path. A
|
198
|
+
# subclass of `AbstractController::Base` may return false. An Email controller
|
199
|
+
# for example does not support paths, only full URLs.
|
200
|
+
def self.supports_path?
|
201
|
+
true
|
202
|
+
end
|
203
|
+
|
204
|
+
def inspect # :nodoc:
|
205
|
+
"#<#{self.class.name}:#{'%#016x' % (object_id << 1)}>"
|
206
|
+
end
|
207
|
+
|
208
|
+
private
|
209
|
+
# Returns true if the name can be considered an action because it has a method
|
210
|
+
# defined in the controller.
|
211
|
+
#
|
212
|
+
# #### Parameters
|
213
|
+
# * `name` - The name of an action to be tested
|
214
|
+
#
|
215
|
+
def action_method?(name)
|
216
|
+
self.class.action_methods.include?(name)
|
217
|
+
end
|
218
|
+
|
219
|
+
# Call the action. Override this in a subclass to modify the behavior around
|
220
|
+
# processing an action. This, and not #process, is the intended way to override
|
221
|
+
# action dispatching.
|
222
|
+
#
|
223
|
+
# Notice that the first argument is the method to be dispatched which is **not**
|
224
|
+
# necessarily the same as the action name.
|
225
|
+
def process_action(...)
|
226
|
+
send_action(...)
|
227
|
+
end
|
228
|
+
|
229
|
+
# Actually call the method associated with the action. Override this method if
|
230
|
+
# you wish to change how action methods are called, not to add additional
|
231
|
+
# behavior around it. For example, you would override #send_action if you want
|
232
|
+
# to inject arguments into the method.
|
233
|
+
alias send_action send
|
234
|
+
|
235
|
+
# If the action name was not found, but a method called "action_missing" was
|
236
|
+
# found, #method_for_action will return "_handle_action_missing". This method
|
237
|
+
# calls #action_missing with the current action name.
|
238
|
+
def _handle_action_missing(*args)
|
239
|
+
action_missing(@_action_name, *args)
|
240
|
+
end
|
241
|
+
|
242
|
+
# Takes an action name and returns the name of the method that will handle the
|
243
|
+
# action.
|
244
|
+
#
|
245
|
+
# It checks if the action name is valid and returns false otherwise.
|
246
|
+
#
|
247
|
+
# See method_for_action for more information.
|
248
|
+
#
|
249
|
+
# #### Parameters
|
250
|
+
# * `action_name` - An action name to find a method name for
|
251
|
+
#
|
252
|
+
#
|
253
|
+
# #### Returns
|
254
|
+
# * `string` - The name of the method that handles the action
|
255
|
+
# * false - No valid method name could be found.
|
256
|
+
#
|
257
|
+
# Raise `AbstractController::ActionNotFound`.
|
258
|
+
def _find_action_name(action_name)
|
259
|
+
_valid_action_name?(action_name) && method_for_action(action_name)
|
260
|
+
end
|
261
|
+
|
262
|
+
# Takes an action name and returns the name of the method that will handle the
|
263
|
+
# action. In normal cases, this method returns the same name as it receives. By
|
264
|
+
# default, if #method_for_action receives a name that is not an action, it will
|
265
|
+
# look for an #action_missing method and return "_handle_action_missing" if one
|
266
|
+
# is found.
|
267
|
+
#
|
268
|
+
# Subclasses may override this method to add additional conditions that should
|
269
|
+
# be considered an action. For instance, an HTTP controller with a template
|
270
|
+
# matching the action name is considered to exist.
|
271
|
+
#
|
272
|
+
# If you override this method to handle additional cases, you may also provide a
|
273
|
+
# method (like `_handle_method_missing`) to handle the case.
|
274
|
+
#
|
275
|
+
# If none of these conditions are true, and `method_for_action` returns `nil`,
|
276
|
+
# an `AbstractController::ActionNotFound` exception will be raised.
|
277
|
+
#
|
278
|
+
# #### Parameters
|
279
|
+
# * `action_name` - An action name to find a method name for
|
280
|
+
#
|
281
|
+
#
|
282
|
+
# #### Returns
|
283
|
+
# * `string` - The name of the method that handles the action
|
284
|
+
# * `nil` - No method name could be found.
|
285
|
+
#
|
286
|
+
def method_for_action(action_name)
|
287
|
+
if action_method?(action_name)
|
288
|
+
action_name
|
289
|
+
elsif respond_to?(:action_missing, true)
|
290
|
+
"_handle_action_missing"
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
# Checks if the action name is valid and returns false otherwise.
|
295
|
+
def _valid_action_name?(action_name)
|
296
|
+
!action_name.to_s.include? File::SEPARATOR
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# :markup: markdown
|
4
|
+
|
5
|
+
module AbstractController
|
6
|
+
module Caching
|
7
|
+
# # Abstract Controller Caching Fragments
|
8
|
+
#
|
9
|
+
# Fragment caching is used for caching various blocks within views without
|
10
|
+
# caching the entire action as a whole. This is useful when certain elements of
|
11
|
+
# an action change frequently or depend on complicated state while other parts
|
12
|
+
# rarely change or can be shared amongst multiple parties. The caching is done
|
13
|
+
# using the `cache` helper available in the Action View. See
|
14
|
+
# ActionView::Helpers::CacheHelper for more information.
|
15
|
+
#
|
16
|
+
# While it's strongly recommended that you use key-based cache expiration (see
|
17
|
+
# links in CacheHelper for more information), it is also possible to manually
|
18
|
+
# expire caches. For example:
|
19
|
+
#
|
20
|
+
# expire_fragment('name_of_cache')
|
21
|
+
module Fragments
|
22
|
+
extend ActiveSupport::Concern
|
23
|
+
|
24
|
+
included do
|
25
|
+
if respond_to?(:class_attribute)
|
26
|
+
class_attribute :fragment_cache_keys
|
27
|
+
else
|
28
|
+
mattr_writer :fragment_cache_keys
|
29
|
+
end
|
30
|
+
|
31
|
+
self.fragment_cache_keys = []
|
32
|
+
|
33
|
+
if respond_to?(:helper_method)
|
34
|
+
helper_method :combined_fragment_cache_key
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module ClassMethods
|
39
|
+
# Allows you to specify controller-wide key prefixes for cache fragments. Pass
|
40
|
+
# either a constant `value`, or a block which computes a value each time a cache
|
41
|
+
# key is generated.
|
42
|
+
#
|
43
|
+
# For example, you may want to prefix all fragment cache keys with a global
|
44
|
+
# version identifier, so you can easily invalidate all caches.
|
45
|
+
#
|
46
|
+
# class ApplicationController
|
47
|
+
# fragment_cache_key "v1"
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# When it's time to invalidate all fragments, simply change the string constant.
|
51
|
+
# Or, progressively roll out the cache invalidation using a computed value:
|
52
|
+
#
|
53
|
+
# class ApplicationController
|
54
|
+
# fragment_cache_key do
|
55
|
+
# @account.id.odd? ? "v1" : "v2"
|
56
|
+
# end
|
57
|
+
# end
|
58
|
+
def fragment_cache_key(value = nil, &key)
|
59
|
+
self.fragment_cache_keys += [key || -> { value }]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Given a key (as described in `expire_fragment`), returns a key array suitable
|
64
|
+
# for use in reading, writing, or expiring a cached fragment. All keys begin
|
65
|
+
# with `:views`, followed by `ENV["RAILS_CACHE_ID"]` or
|
66
|
+
# `ENV["RAILS_APP_VERSION"]` if set, followed by any controller-wide key prefix
|
67
|
+
# values, ending with the specified `key` value.
|
68
|
+
def combined_fragment_cache_key(key)
|
69
|
+
head = self.class.fragment_cache_keys.map { |k| instance_exec(&k) }
|
70
|
+
tail = key.is_a?(Hash) ? url_for(key).split("://").last : key
|
71
|
+
|
72
|
+
cache_key = [:views, ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"], head, tail]
|
73
|
+
cache_key.flatten!(1)
|
74
|
+
cache_key.compact!
|
75
|
+
cache_key
|
76
|
+
end
|
77
|
+
|
78
|
+
# Writes `content` to the location signified by `key` (see `expire_fragment` for
|
79
|
+
# acceptable formats).
|
80
|
+
def write_fragment(key, content, options = nil)
|
81
|
+
return content unless cache_configured?
|
82
|
+
|
83
|
+
key = combined_fragment_cache_key(key)
|
84
|
+
instrument_fragment_cache :write_fragment, key do
|
85
|
+
content = content.to_str
|
86
|
+
cache_store.write(key, content, options)
|
87
|
+
end
|
88
|
+
content
|
89
|
+
end
|
90
|
+
|
91
|
+
# Reads a cached fragment from the location signified by `key` (see
|
92
|
+
# `expire_fragment` for acceptable formats).
|
93
|
+
def read_fragment(key, options = nil)
|
94
|
+
return unless cache_configured?
|
95
|
+
|
96
|
+
key = combined_fragment_cache_key(key)
|
97
|
+
instrument_fragment_cache :read_fragment, key do
|
98
|
+
result = cache_store.read(key, options)
|
99
|
+
result.respond_to?(:html_safe) ? result.html_safe : result
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Check if a cached fragment from the location signified by `key` exists (see
|
104
|
+
# `expire_fragment` for acceptable formats).
|
105
|
+
def fragment_exist?(key, options = nil)
|
106
|
+
return unless cache_configured?
|
107
|
+
key = combined_fragment_cache_key(key)
|
108
|
+
|
109
|
+
instrument_fragment_cache :exist_fragment?, key do
|
110
|
+
cache_store.exist?(key, options)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Removes fragments from the cache.
|
115
|
+
#
|
116
|
+
# `key` can take one of three forms:
|
117
|
+
#
|
118
|
+
# * String - This would normally take the form of a path, like
|
119
|
+
# `pages/45/notes`.
|
120
|
+
# * Hash - Treated as an implicit call to `url_for`, like `{ controller:
|
121
|
+
# 'pages', action: 'notes', id: 45}`
|
122
|
+
# * Regexp - Will remove any fragment that matches, so `%r{pages/\d*/notes}`
|
123
|
+
# might remove all notes. Make sure you don't use anchors in the regex (`^`
|
124
|
+
# or `$`) because the actual filename matched looks like
|
125
|
+
# `./cache/filename/path.cache`. Note: Regexp expiration is only supported
|
126
|
+
# on caches that can iterate over all keys (unlike memcached).
|
127
|
+
#
|
128
|
+
#
|
129
|
+
# `options` is passed through to the cache store's `delete` method (or
|
130
|
+
# `delete_matched`, for Regexp keys).
|
131
|
+
def expire_fragment(key, options = nil)
|
132
|
+
return unless cache_configured?
|
133
|
+
key = combined_fragment_cache_key(key) unless key.is_a?(Regexp)
|
134
|
+
|
135
|
+
instrument_fragment_cache :expire_fragment, key do
|
136
|
+
if key.is_a?(Regexp)
|
137
|
+
cache_store.delete_matched(key, options)
|
138
|
+
else
|
139
|
+
cache_store.delete(key, options)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def instrument_fragment_cache(name, key, &block) # :nodoc:
|
145
|
+
ActiveSupport::Notifications.instrument("#{name}.#{instrument_name}", instrument_payload(key), &block)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|