The new params.expect
method in Rails 8 improves parameter filtering, addressing issues with malformed input and enhancing security. It provides a cleaner, more explicit way to enforce the structure and types of incoming parameters.
What changed
-
Replaces
require
andpermit
: Combines both methods for concise parameter validation. - Explicit Array Handling: Requires double array syntax to define arrays of hashes, improving clarity.
-
Enhanced Validation: Ensures expected parameter structure, rejecting malformed input with a 400 error instead of a 500 Error.
Invalid input structures raiseActionController::ParameterMissing
rather thanNoMethodError
when a disallowed type (e.g., string instead of hash or array) is provided for the permitted attributes.
Example
Basic Usage
# Old before Rails 8
user_params = params.require(:user).permit(:name)
# New since Rails 8
user_params = params.expect(user: [:name])
Allowing Arrays
For an array of hashes:
# Params to allow: { "comments" => [ {"text" => "Hi!"}, {"id" => "Yep."} ] }
# For the url format comments[][text]=Hi!&comments[][id]=Yep.
params = ActionController::Parameters.new({ "comments" =>
[
{"text" => "Hi!"},
{"text" => "Yep."}
]
})
params.expect(comments: [[:text]])
# => [#<ActionController::Parameters {"text" => "Hi!"} permitted: true>, #<ActionController::Parameters {"text" => "Yep."} permitted: true>]
# Params to allow: { "posts" => { id: 12, tags: [ { name: "card" }, { name: "blog" } ] } }
# For the url format posts[id]=12&posts[tags][][name]=blog&posts[tags][][name]=card
params = ActionController::Parameters.new({ "posts" => {
id: 12,
tags: [
{"name" => "blog"},
{"name" => "card"}
]
}})
params.expect(posts: [tags: [[:name]]])
# => #<ActionController::Parameters {"tags" => [#<ActionController::Parameters {"name" => "blog"} permitted: true>, #<ActionController::Parameters {"name" => "card"} permitted: true>]} permitted: true>
For an array of strings:
# Params to allow: { "posts" => { id: 12, tags: ["card", "blog"] } }
# For the url format posts[id]=12&posts[tags][]=blog&posts[tags][]=card
params = ActionController::Parameters.new({ "posts" => {
id: 12,
tags: [
"blog",
"card"
]
}})
params.expect(posts: [:id, tags: []])
#<ActionController::Parameters {"id" => 12, "tags" => ["blog", "card"]} permitted: true>
Further resources
Martin Emde, the creator of the pull request Show archive.org snapshot wrote two great blog posts on the topic:
-
How to: Rails
params.expect
Show archive.org snapshot -
How to convert to
params.expect
in Rails 8.0 Show archive.org snapshot
Using Strong Parameters
We also have the following two cards for more details and potential gotchas on using strong parameters:
Posted by Felix Eschey to makandra dev (2025-01-20 06:15)