Add Parameters#expect to safely filter and require params#51674
Add Parameters#expect to safely filter and require params#51674dhh merged 4 commits intorails:mainfrom
Parameters#expect to safely filter and require params#51674Conversation
ActionController::Parameters#mandate
ActionController::Parameters#mandateParameters#mandate
9b6b42c to
acd1c49
Compare
|
@martinemde please add tests and a changelog entry |
|
I wonder if we should just handle these NoMethodErrors differently. It feels weird to return a 500 when the error is the "the user's fault". Maybe we could return a 4XX somehow? |
|
Let's move on with this one. @dhh already reviewed the API and said it looks promising. Can you write tests for it and prefer using it to |
|
Fixes #52463 |
|
I'll update the PR soon |
Actually, if I'm not mistaken, fixes only half of it. |
acd1c49 to
96041b5
Compare
|
I'm pushing up work as I finish. Thanks for the feedback. Should have it done soon. (I'll squash when it's ready) As I've been working on this I thought of an alternate name. What do you think? params.expect(person: %i[name, age])After typing mandate over and over, I'm not totally in love with it, but I don't feel strongly. |
|
Seems good so far. I find However, seeing as |
|
@dari-us maybe The existing configuration makes sense. Logging can be useful in dev but would be extra noise in most production applications. This implies to me that logging is an environment config and raising should be controlled by how the methods are called. Please correct me if you think otherwise. If we added |
|
Regarding your comment @MatheusRich, I never got to respond.
This was what motivated me to create this. It's certainly wrong to return 500 when the client caused the problem, but once
|
56fbb57 to
ebd455d
Compare
ebd455d to
7ae40bb
Compare
|
I switched the name from I'm doing one more pass on the guides to try to find non-obvious uses. Otherwise this is ready for code review (and please call out any documentation that you think should be fixed, if I missed it) I'm working on fixing the test failures. |
7ae40bb to
4f03eb7
Compare
|
@martinemde Yeah, global config for logging and raising/ignoring via method call is fine by me and I think makes sense for the broad majority of apps. I think at this point, On another note, sadly the use case how to replace Also, I would love to make a followup PR to
Hopefully I can spare some time on that soon. |
|
@dari-us, ok, I understand now what you mean. The fact of how permit works when applied to params "root" means it would consider any other params to be unpermitted. This explains something I was noticing on rubygems.org, which is that dev was logging more unpermitted params than usual. Possible fix, but maybe too ugly: Edit: thinking ahead about As for the other methods, I think you're right. The |
2276ff4 to
4fc0c3e
Compare
|
Excellent work, guys! This is a very nice upgrade. We'll need to also upgrade the templates in the jbuilder gem, since they're used by default. Probably have to have a Rails version toggle where we use expect when 8.0+ and whatever is there before that. @martinemde want to take a stab at that too? |
|
Nice change, silents some noise in bug notifications. Should there be a rubocop rule for it? |
No. Don't need to nag people about this. They can upgrade to the new syntax as they see fit and new apps will automatically guide folks in that direction. |
|
Nice API! |
|
@p8 I hardly see that as a problem, at least I cannot remember ever seeing |
) * `Parameters#expect` safely filters and requires params * `Parameters#expect!` raises unhandled exception on missing params * Add public/400.html file rendered on bad request --------- Co-authored-by: dari-us <[email protected]>
|
I can see non-native English speakers or people with dyslexia having problems with this - copying the guide documentation and wondering why things aren't working as expected. As this API seems to be more strict than For example |
|
Appreciate the feedback here, but this bikesheed has already been painted, @p8. We're moving on to other bikesheeds now 😄 |
|
I took a stab at updating the jbuilder templates here: rails/jbuilder#573. Also fixed a minor Rubocop issue introduced by this PR here: #52928. |
) * `Parameters#expect` safely filters and requires params * `Parameters#expect!` raises unhandled exception on missing params * Add public/400.html file rendered on bad request --------- Co-authored-by: dari-us <[email protected]>
Motivation / Background
I've been hunting around trying to fix the problem with the default, recommended way of handling parameters in Rails.
This is fine until someone using your app starts messing with the parameters and causing 500 errors by passing:
This causes a NoMethodError because
permitis called on"string".The recommendation is not the best way. Instead, the first statement should be written like this:
Detail
In this PR, I propose a new method on ActionController::Parameters that safely handles params filtering in one method, cuts down on ignorable errors caused by params tampering, and improves the specificity of param types.
In order to ensure consistent filtering of hashes vs arrays in params,
expectintroduces a new Array matching syntax using a double array[[:attr]]. (this example uses shorthand for all but the first example to make it more readable. The hashes returned are actually permitted ActionController::Parameter objects)As you can see,
permitwill expect an array when the "double array" syntax is used, but defaults to the old behavior of allowing both arrays and hashes otherwise, maintaining backwards compatibility.expecton the other hand is strict in for both arrays and hashes.This pull request also adds the
expect!method.expect!raises an unhandled error in cases whereexpectwould raise a handled error that would return a 400 bad request. The unhandled error can be used in cases where it is important to be alerted about a client using incorrect syntax (such as a private internal API where the client should be fixed).Adds a 400.html template used to render the 400 bad request response.
Additional information
Related PRs and issues that address this problem:
Checklist
Before submitting the PR make sure the following are checked:
[Fix #issue-number]