This change incorporates to Rails a feature called error_highlight that
has been available since Ruby 3.1. This allow Rails' error report screen
to display the fine-grained location where an error occurred (not only a
line number but also beginning and end column numbers of the code
fragment).
For ErrorHighlight, see https://bugs.ruby-lang.org/issues/17930 in
detail.
To use error_highlight, ExceptionWrapper now prefers
`Exception#backtrace_locations` (since Ruby 2.1), which returns an array
of `Thread::Backtrace::Location`s, instead of `Exception#backtrace`.
This is because error_highlight requires `Thread::Backtrace::Location`
to locate the column where an error was raised.
Co-Authored-By: John Hawthorn <john@hawthorn.email>
Co-Authored-By: Jean Boussier <jean.boussier@gmail.com>
The various LogSubscriber subclasses tend to subscribe to events
but then end up doing nothing if the log level is high enough.
But even if we end up not logging, we have to go through the
entire notification path, record timing etc.
By allowing subscribers to dynamically bail out early, we can
save a lot of work if all subscribers are silenced.
Right now many helpers have to deal with two modes of operation to
capture view output.
The main one is to swap the `@output_buffer` variable with a new buffer.
But since some view implementations such as `builder` keep a reference
on the buffer they were initialized with, this doesn't always work.
So additionally, the various capturing helpers also record the buffer
length prior to executing the block, and then `slice!` the buffer back
to its original size.
This is wasteful and make the code rather unclear.
Now that `OutputBuffer` is a delegator, I'd like to refactor all this
so that:
- @output_buffer is no longer re-assigned
- A single OutputBuffer instance is used for the entire response rendering
- Instead capturing is done through `OutputBuffer#capture`
Once the above is achieved, it should allow us to enabled Erubi's
`:chain_appends` option and get some reduced template size and some
performance.
Not re-assigning `@output_buffer` will also allow template to access
the local variable instead of an instance variable, which is cheaper.
But more importantly, that should make the code easier to understand
and easier to be compatible with `StreamingBuffer`.
Routes take a long time to draw. Over time, a Rails app can become slow
to boot simply because of how many routes it has. This script can be
used to detect routes that are drawn, but aren't actually valid.
Removing routes this script detects can help speed up your app and
remove dead code.
Example:
```
> bin/rails routes --unused
Found 2 unused routes:
Prefix Verb URI Pattern Controller#Action
one GET /one(.:format) action#one
two GET /two(.:format) action#two
```
Follow-up to #45501.
The Rack base class that `CookieStore` inherits from [always sets
`:same_site`][1]. Thus, `options.key?(:same_site)` always returns true
for session cookies, preventing a default value from being set.
It would be possible to change Rack to conditionally set `:same_site`,
but, from Rack's perspective, it has no reason to not set `:same_site`,
because it treats a `nil` value the same as no value.
Therefore, this commit specifies a default `:same_site` in `CookieStore`,
which simply defers to `request.cookies_same_site_protection` as
`CookieJar` does.
Fixes#45681.
[1]: https://github.com/rack/rack/blob/2.2.4/lib/rack/session/abstract/id.rb#L398-L402
This commit just ensures we're green with the main branch of rack test.
The changes are things we should have done anyway, and are backwards
compatible with older versions of rack test
Since 7ccaa125ba it's not been possible to not include `SameSite` on your cookies. `SameSite` is recommended, but it's not a required field, and you should be able to opt out of it.
This PR introduces that ability: you can opt out of `SameSite` by passing `same_site: false`.
```ruby
cookies[:foo] = { value: "bar", same_site: false }
```
Previously, this incorrectly set the `SameSite` attribute to the value of the `cookies_same_site_protection` setting. https://github.com/rails/rails/pull/44934 added docs saying that you could pass `nil` as a value, but that also would fall back to the default (`:lax`).
Fixes https://github.com/rails/rails/issues/45489
- Adds `anchor: true` to the Action Cable server mount, so that it only strictly matches `/cable` rather than anything that starts with that.
- Uses `reverse_merge` instead of `merge` in `Mapper#mount`, so that you can override these options if you need to.
In minitest/minitest@6e06ac9 minitest changed such that it now accepts
`kwargs` instead of requiring kwargs to be shoved into the args array.
This is a good change but required some updates to our test code to get
the new version of minitest passing.
Changes are as follows:
1) Lock minitest to 5.15 for Ruby 2.7. We don't love this change but
it's pretty difficult to get 2.7 and 3.0 to play nicely together with
the new kwargs changes. Dropping 2.7 support isn't an option right
now for Rails. This is safe because all of the code changes here are
internal methods to Rails like assert_called_with. Applications
shouldn't be consuming them as they are no-doc'd.
2) Update the `assert_called_with` method to take any kwargs but also
the returns kwarg.
3) Update callers of `assert_called_with` to move the kwargs outside the
args array.
4) Update the message from marshaled exceptions. In 5.16 the exception
message is "result not reported" instead of "Wrapped undumpable
exception".
Co-authored-by: Matthew Draper <matthew@trebex.net>
activerecord-session_store was removed in 0ffe190, and has been
displaying a special error message when missing since Rails 4.0.
Replace the specific error message so that third party stores get nicer
error handling as well
This documentation was correct when it was written in 6e75455, however
`headers` has moved a few times since:
- added to ActionController::Http in 216309c as part of the new_base
- Http was renamed to Metal in 52798fd
- headers was changed from an independent hash to a delegation in
51c7ac1 and 54becd1
Added docs for Metal#request, Metal#response, and Metal#headers that can
be linked to from Response. The recommendation to use Metal delegation
methods instead of methods on Response was also removed due to a number of
docs/guides demonstrating the opposite.
In
f075be3dcb
did_you_mean and error_highlight now use `detailed_message` over
`message` to display errors.
For cases where we are testing `message`, in 3.2 and above we need to
test against `detailed_message` instead.
As far as I can tell in a Rails console when these errors are raised the
`detailed_message` is used so we shouldn't need to make other changes to
Rails. The only case where this isn't true is in the Railties changes -
we are explicitly formatting the did you mean message so we need to be
sure to call `detailed_message` here.
This fixes most of the failing tests for ruby-trunk.
Previously, as of 80aaa111884247e6aa17b7bbab268c7719847521,
ActionController::Parameters has defined hash as:
[@parameters.hash, @permitted].hash
Defining hash means that eql? must be defined, and eql? must be at
least as strict as the hash value generated. That is, for any two
objects which return a different hash value, `a.eql?(b)` should return
false. Otherwise, because hash values have a random seed added, and in
some cases have only some of their bits compared, their behaviour in a
hash becomes undefined. Previously we were breaking this expectation by
allowing a deprecated comparison between Parameters and a plain hash.
This commit fixes eql? to match hash, only returning true when the class
matches as well as the permitted? and parameters values (ie. eql? never
allows the deprecated relaxed equality branch).
This also adds the class to the hash and eql? check, which previously
wasn't there, which isn't strictly necessary to fix this but I think is
a best practice.
Since 5745a3c0928ee5604ce80af19348efb42189f1d6, if a controller defines
a `headers` method it will be called by this line, and the return value
will be mutated. This was also preventing the "Vary" header from being
sent to the client.
Co-authored-by: Oleksandr Bezruchenko <alex.bezruchenko@intercom.io>
Co-authored-by: Iliana Hadzhiatanasova <iliana.hadzhiatanasova@intercom.io>
Kernel#method was redefined so one couldn't do for instance.
method(:POST).source_location
Now when called without arguments it returns the method of the
request and when called with arguments it uses Kernel#method
Which makes debugging easier
Co-authored-by: Joé Dupuis <joe@dupuis.io>
Fixes https://github.com/rails/rails/issues/45034
Currently helpers that are generated using `helper_method` cannot be used in `content_security_policy` and `permissions_policy`, this is because the use of `yield` causes `self` to be set incorrectly. By using `instance_exec` we ensure the scoping is correct so that you can access the same methods you'd be able to if you wrote your own `before_action`.
Currently if you use `helper_method` to define a method, and inside that method you get an error, the backtrace is off by one line.
This PR fixes that so that the backtrace now points to the line where you called `helper_method`.
It is best practice to include the unexpected value in logs
and error message as it can often make it much easier to understand
where the error come from.
Fix: https://github.com/rails/rails/issues/44923
The fix may seem very ad hoc, but this methods assumes all params
come from Rack, hence are mutable. So checking for frozen is a decent
proxy for ignoring the router defaults.
Add the default status code returned by `ActionDispatch::Routing::Redirection#redirect` in the RDoc comment.
Include an example
Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
As the `reset` method is called without further conditionals in line 342, all
custom strategies must implement this method as well.
This may have been an oversight in one of the many iterations of #44283.
It was added in 66f8997 to be compatible with Rack::ContentLength.
However, to_ary was removed from Rack::Response in 2.1.0, and
Rack::ContentLength stopped checking for response bodies to define
to_ary in 2.2.0. In addition, Rack 3 will eventually require response
bodies that define to_ary to have a proper return value.
Since the minimum supported Rack version is already 2.2.0, to_ary can
be safely removed now.
We already have a commit CSRF method exposed via the request object
since it's used by the implementation when committing the session, so
having a similar reset CSRF method exposed makes sense, and hides some
of the internal complexity of calling that method via the controller
instance.
It will also facilitate reaching out to the reset CSRF logic from other
libraries like Devise, to more easily integrate with this change.
Every time I write `config.cache_classes` I have to pause for a moment to make
sure I get it right. It makes you think.
On the other hand, if you read `config.enable_reloading = true`, does the
application reload? You do not need to spend 1 cycle of brain CPU to nod.
PR #23733 was supposed to deprecate and remove the ability to compare
Hash objects with AC::Parameters objects. Unfortunately it seems that
we still accidentally support that.
This PR adds a deprecation warning so that we can remove it in the
future.
Allow `ActionController::Parameters.to_h` to receive a block to provide
parity with `Hash#to_h`. The provided block recieves `key, value` and
yields a two-element array/keypair which can be transformed in the
resulting Hash.
https://ruby-doc.org/core-2.7.5/Hash.html#method-i-to_h
This has been broken since the logging context was added in
6be9c498bccd8dbc99b4b451841fcf73c7061d48
Also added a higher level test to ensure that this isn't broken again in
the future.
In environments where the routes aren't eager loaded such as development or
test a race condition could occur where two requests would trigger the
`offsets` method in `ActionDispatch::Journey::Path::Pattern` and the early
return for `@offsets` would be triggered by the initialisation of the
instance variable to `[0]` before the rest of the method had completed.
Fixes#43431.
In #44608 the application/problem+json content type was added as a
default alias for json but as the test only fails intermittently
it wasn't picked up during PR review. It also restores the rootless
test that was reverted due to it failing for the same reason.
This builds on the environment variables added in https://github.com/rails/rails/pull/36545
Being able to request `html` or `screenshot` from test code is nice as it means you can do this selectively per-screenshot, rather than screenshotting/HTML dumping everything when running a test.
One feature of the content security policy DSL, though undocumented,
is that it will not generate headers for non-HTML responses, even if a
configuration is explicitly provided. While it may not seem obvious
that anyone would want to send this header in an API response, Mozilla
Observatory, for instance, recommends the following for API responses:
`Content-Security-Policy: default-src 'none'; frame-ancestors 'none'`
(source: https://observatory.mozilla.org/faq/)
The Secure Headers gem also makes recommendations about the content
security policy for API responses: https://github.com/github/secure_headers#api-configurations
As such, this removes the HTML guard clause from the
`ContentSecurityPolicy` middleware.
These docs reference https://blog.gingerlime.com/2012/rails-ip-spoofing-vulnerabilities-and-protection/ pretty early, but this site is no longer online. Rather than relying on a third party blog post, the docs should be self-explanatory as much as possible.
- I removed the link to the blog post from the header Later in the docs I left a link to a [web archive version](https://web.archive.org/web/20170626095448/https://blog.gingerlime.com/2012/rails-ip-spoofing-vulnerabilities-and-protection/) of the post.
- Added a note about removing the middleware if you don't use a proxy. This was suggested in the Gingerlime blog post and didn't make it into the docs, but I think it's worth flagging for extreme cases.
In general I think the docs do a good job of covering most of the advice in the Gingerlime blog post except the bit about removing this middleware.
Otherwise it might only be loaded once `url_for` is called:
```
from bundler/gems/rails-5772ecd7d568/actionpack/lib/action_dispatch/routing/routes_proxy.rb:7:in `<module:Routing>'
from bundler/gems/rails-5772ecd7d568/actionpack/lib/action_dispatch/routing/routes_proxy.rb:6:in `<module:ActionDispatch>'
from bundler/gems/rails-5772ecd7d568/actionpack/lib/action_dispatch/routing/routes_proxy.rb:5:in `<main>'
from gems/bootsnap-1.10.3/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
from gems/bootsnap-1.10.3/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
from gems/zeitwerk-2.5.4/lib/zeitwerk/kernel.rb:35:in `require'
from bundler/gems/rails-5772ecd7d568/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb:214:in `polymorphic_method'
from bundler/gems/rails-5772ecd7d568/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb:116:in `polymorphic_url'
from bundler/gems/rails-5772ecd7d568/actionpack/lib/action_dispatch/routing/url_for.rb:187:in `full_url_for'
from bundler/gems/rails-5772ecd7d568/actionpack/lib/action_dispatch/routing/url_for.rb:170:in `url_for'
```
https://github.com/rails/rails/pull/43209 immediately rejects
the request if no password is passed, but there are legitimate
uses for accepting authentication without a password.
These classes are relatively small, however they include lots of
modules as helpers. And if any of the included module hold constants
including it cause the global constant cache to be invalidated
which is really bad for performance.
So when eager loading is enabled we create all the possible classes
as part of the application boot.
Calling `skip_forgery_protection` without first calling
`protect_from_forgery`--either manually or through default
settings--raises an `ArgumentError` because `verify_authenticity_token`
has not been defined as a callback.
Since Rails 7.0 adds `skip_forgery_protection` to the
`Rails::WelcomeController` (PR #42864), this behavior means that setting
`default_protect_from_forgery` to false and visiting the Rails Welcome
page (`/`) raises an error.
This behavior also created an issue for `ActionMailbox` that was
previously fixed in the Mailbox controller by running
`skip_forgery_protection` only if `default_protect_from_forgery` was
true (PR #35935).
This PR addresses the underlying issue by setting the `raise` option for
`skip_before_action` to default to false inside
`skip_forgery_protection`.
The fix is implemented in `request_forgery_protection.rb`. The change to
`ActionMailbox`'s `base_controller.rb` removes the now-unnecessary
check of `default_protect_from_forgery`.
The tests added in `request_forgery_protection_test.rb` and
`routing_test.rb` both raise an error when run against the current
codebase and pass with the changes noted above.