Passing relative paths into form_for and related helpers led to invalid
token generations, as the tokens did not match the request.path on the
POST endpoint. Variants, such as:
form_for url:
* ""
* "./"
* "./post_one"
* "post_one"
are now handled according to [RFC 3986 5.2 - 5.4](https://tools.ietf.org/html/rfc3986#section-5.2)
Limitations: double dots are not handled (../../path)
relevant issue: #31191
Given that the limiter implementation provided by Kredis is a simple
increment with a limit, all `ActiveSupport::Cache` already provide that
same capability, with a wide range of backing stores, and not just Redis.
This even allow to use SolidCache has a backend if you so desire.
If we feel particularly fancy, we could also accept a more generic
limiter interface to better allow users to swap the implementation
for better algorithms such as leaky-bucket etc.
Adds support for with_routing test helpers in ActionDispatch::IntegrationTest.
Previously, this helper didn't work in an integration context because
the rack app and integration session under test were not mutated.
Because controller tests are integration tests by default, we should
support test routes for these kinds of test cases as well.
When the webdrivers gem is not present (which is the default scenario in
Rails 7.1+), the Selenium `driver_path` starts out as `nil`. This means
the driver is located lazily, and deferred until a system test is run.
If parallel testing is used, this leads to a race condition, where each
worker process tries to resolve the driver simultaneously. The result is
an error as described in #49906.
This commit fixes the race condition by changing the implementation of
`Browser#preload`. The previous implementation worked when `driver_path`
was set to a Proc by the `webdrivers` gem, but doesn't work when the
`webdrivers` gem is not being used and the `driver_path` is `nil`.
`Browser#preload` now uses the `DriverFinder` utility provided by the
`selenium-webdriver` gem to eagerly resolve the driver path if needed.
This will ensures that `driver_path` is set before parallel test workers
are forked.
Fixes#49906.
Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
Ruby 3.3.0 is going to start warning for racc not being specififed as a
dependency, and Ruby 3.4.0 will raise if it is not specified.
This commit prevents those issues by adding racc to the Action Pack
gemspec, since `racc/parser` is a runtime dependency of the Journey
parser.
When [rails/rails#20868][] changed the `ActionController::Parameters`
ancestory from `HashWithIndifferentAccess` to `Object`, support for
`#deep_merge` and `#deep_merge!` were omitted.
This commit restores support by integrating with
[ActiveSupport::DeepMergeable](./activesupport/lib/active_support/deep_mergeable.rb).
[rails/rails#20868]: https://github.com/rails/rails/pull/20868
Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
This commit adds `extract_value` method to `ActionController::Parameters`
as a primary way to extract composite `id` values serialized from
`ActiveRecord::Base#to_param` called on a model with a composite primary key.
Both `Nokogiri` and `Minitest` have merged the PRs mentioned to
integrate support for Ruby's Pattern matching
(https://github.com/sparklemotion/nokogiri/pull/2523 and
https://github.com/minitest/minitest/pull/936, respectively).
This commit adds coverage for those new assertions, and incorporates
examples into the documentation for the `response.parsed_body` method.
In order to incorporate pattern-matching support for JSON responses,
this commit changes the response parser to call `JSON.parse` with
[object_class: ActiveSupport::HashWithIndifferentAccess][object_class],
since String instances for `Hash` keys are incompatible with Ruby's
syntactically pattern matching.
For example:
```ruby
irb(main):001:0> json = {"key" => "value"}
=> {"key"=>"value"}
irb(main):002:0> json in {key: /value/}
=> false
irb(main):001:0> json = {"key" => "value"}
=> {"key"=>"value"}
irb(main):002:0> json in {"key" => /value/}
.../3.2.0/lib/ruby/gems/3.2.0/gems/irb-1.7.4/lib/irb/workspace.rb:113:in `eval': (irb):2: syntax error, unexpected terminator, expecting literal content or tSTRING_DBEG or tSTRING_DVAR or tLABEL_END (SyntaxError)
json in {"key" => /value/}
^
.../ruby/3.2.0/lib/ruby/gems/3.2.0/gems/irb-1.7.4/exe/irb:9:in `<top (required)>'
.../ruby/3.2.0/bin/irb:25:in `load'
.../ruby/3.2.0/bin/irb:25:in `<main>'
```
When the Hash maps String keys to Symbol keys, it's able to be pattern
matched:
```ruby
irb(main):005:0> json = {"key" => "value"}.with_indifferent_access
=> {"key"=>"value"}
irb(main):006:0> json in {key: /value/}
=> true
```
[object_class]: https://docs.ruby-lang.org/en/3.2/JSON.html#module-JSON-label-Parsing+Options
Previously, when a Request had a non-authorized HTTP_HOST but an
authorized HTTP_X_FORWARDED_HOST, the HTTP_X_FORWARDED_HOST value would
be displayed as the one being blocked. However, this could be confusing
for users since that value would already be added to `config.hosts`.
This commit addresses the issue by tweaking how the blocked host is
displayed. Instead of always displaying Request#host (which will return
X_FORWARDED_HOST when present whether or not that's the host being
blocked), each host being blocked will be displayed on its own.
Co-authored-by: Daniel Schlosser <Eusebius1920@users.noreply.github.com>
The naming difference between the test harness' [file_fixture][] helper
made available through Active Support (along with the
`file_fixture_path` configuration value) and the integration test
harness' [fixture_file_upload][] is a constant source of confusion and
surprise.
Since Active Support is more ubiquitous, this commit renames the
`fixture_file_upload` method to `file_fixture_upload` to match the order
of words in `file_fixture` and `file_fixture_path`.
To preserve backwards compatibility, declare a `fixture_file_upload`
alias to be preserved into the future (or removed at a future point in
time).
[file_fixture]: https://edgeapi.rubyonrails.org/classes/ActiveSupport/Testing/FileFixtures.html#method-i-file_fixture
[fixture_file_upload]: https://edgeapi.rubyonrails.org/classes/ActionDispatch/TestProcess/FixtureFile.html#method-i-fixture_file_upload
Accept headers allow parameters to be passed. They can contain quotes
that need to be handled differently. These quoted strings can contain
commas, which are not considered as delimiters of accept headers.
Additionally, all parameters before the q-parameter should be used to
lookup the media-type as well. If no media-type with the parameters is
found, a fallback is introduced to the media-type without any parameters
to keep the same functionality as before.
Fix#48052
The url_for helper now supports a new option called `bind_params`.
This is very useful in situations where you only want to add a required
param that is part of the route's URL but for other route not append an
extraneous query param.
Given the following router...
```ruby
Rails.application.routes.draw do
scope ":account_id" do
get 'dashboard' => 'pages#dashboard', as: :dashboard
get 'search/:term' => 'search#search', as: :search
end
delete 'signout' => 'sessions#destroy', as: :signout
end
```
And given the following `ApplicationController`
```ruby
class ApplicationController < ActionController::Base
def default_url_options
{ bind_params: { account_id: "foo" } }
end
end
```
The standard URLHelpers will now behave as follows:
```ruby
dashboard_path # => /foo/dashboard
dashboard_path(account_id: "bar") # => /bar/dashboard
signout_path # => /signout
signout_path(account_id: "bar") # => /signout?account_id=bar
search_path("quin") # => /foo/search/quin
```
Background
----------
During integration tests, it is desirable for the application to respond
as closely as possible to the way it would in production. This improves
confidence that the application behavior acts as it should.
In Rails tests, one major mismatch between the test and production
environments is that exceptions raised during an HTTP request (e.g.
`ActiveRecord::RecordNotFound`) are re-raised within the test rather
than rescued and then converted to a 404 response.
Setting `config.action_dispatch.show_exceptions` to `true` will make the
test environment act like production, however, when an unexpected
internal server error occurs, the test will be left with a opaque 500
response rather than presenting a useful stack trace. This makes
debugging more difficult.
This leaves the developer with choosing between higher quality
integration tests or an improved debugging experience on a failure.
I propose that we can achieve both.
Solution
--------
Change the configuration option `config.action_dispatch.show_exceptions`
from a boolean to one of 3 values: `:all`, `:rescuable`, `:none`. The
values `:all` and `:none` behaves the same as the previous `true` and
`false` respectively. What was previously `true` (now `:all`) continues
to be the default for non-test environments.
The new `:rescuable` value is the new default for the test environment.
It will show exceptions in the response only for rescuable exceptions as
defined by `ActionDispatch::ExceptionWrapper.rescue_responses`. In the
event of an unexpected internal server error, the exception that caused
the error will still be raised within the test so as to provide a useful
stack trace and a good debugging experience.
This commit adds support for `:message_pack` and `:message_pack_allow_marshal`
as serializers for `config.action_dispatch.cookies_serializer`, just
like `config.active_support.message_serializer`.
The `:message_pack` serializer can fall back to deserializing with
`AS::JSON`, and the `:message_pack_allow_marshal` serializer can fall
back to deserializing with `AS::JSON` or `Marshal`. Additionally, the
`:marshal`, `:json`, and `:hybrid` / `:json_allow_marshal` serializers
can now fall back to deserializing with `AS::MessagePack`. These
behaviors make it easier to migrate between cookies serializers.
Rails has incorrectly been adding leading dots to cookie domain values
when the `domain: :all` option is present.
This leading dot was required in cookies based on [RFC 2965][rfc2965]
(October 2000), but [RFC 6265][rfc6265] (April 2011) changed that
behaviour, making a leading dot strictly incorrect. Todays browsers aim
to confirm to RFC6265 with repect to cookies.
The new behaviour is that *any* cookie with an explicitly passed domain
is sent to all matching subdomains[[ref][mdn]]. For a server to indicate
that only the exact origin server should receive the cookie, it should
instead pass *no* domain attribute.
Despite the change in behaviour, browser devtools often display a cookie
domain with a leading dot to indicate that it is valid for subdomains -
this prefixed domain is *not* necessarily the raw value that was passed
in the Set-Cookie header. This explains why it's a common belief among
developers that the leading dot is required.
RFC6265 standard gives UAs an algorithm to handle old-style cookie
domain parameters (they can drop a leading dot if present), so it's
unlikely that this error would ever have had any effect on web browsers.
However, cookies generated this way can't be processed by Ruby's own
CGI::Cookie class:
> CGI::Cookie.new "domain" => ".foo.bar", "name" => "foo"
ArgumentError: invalid domain: ".foo.bar"
Newer versions of the Ruby CGI library accomodate the same fallback
behaviour (dropping the extra dot) but this isn't a justification for it
being the right way to set a cookie.
[mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#domain_attribute
[rfc2965]: https://www.rfc-editor.org/rfc/rfc2965#section-3.2
[rfc6265]: https://www.rfc-editor.org/rfc/rfc6265#section-4.1.1
Expands the search field on the rails/info/routes page to also search:
* Route name (with or without a _path and _url extension)
* HTTP Verb (eg. GET/POST/PUT etc.)
* Controller#Action
because it's not obvious that the search field is currently only
restricted to the route paths.