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
requireandpermit: 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::ParameterMissingrather thanNoMethodErrorwhen 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.expectShow archive.org snapshot -
How to convert to
params.expectin 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)