instance method
expect
Ruby on Rails 8.0.4
Since v8.0.4Available in: v8.0.4 v8.1.2
Signature
expect(*filters)
expect is the preferred way to require and permit parameters. It is safer than the previous recommendation to call permit and require in sequence, which could allow user triggered 500 errors.
expect is more strict with types to avoid a number of potential pitfalls that may be encountered with the .require.permit pattern.
For example:
params = ActionController::Parameters.new(comment: { text: "hello" }) params.expect(comment: [:text]) # => #<ActionController::Parameters { text: "hello" } permitted: true> params = ActionController::Parameters.new(comment: [{ text: "hello" }, { text: "world" }]) params.expect(comment: [:text]) # => ActionController::ParameterMissing: param is missing or the value is empty or invalid: comment
In order to permit an array of parameters, the array must be defined explicitly. Use double array brackets, an array inside an array, to declare that an array of parameters is expected.
params = ActionController::Parameters.new(comments: [{ text: "hello" }, { text: "world" }]) params.expect(comments: [[:text]]) # => [#<ActionController::Parameters { "text" => "hello" } permitted: true>, # #<ActionController::Parameters { "text" => "world" } permitted: true>] params = ActionController::Parameters.new(comments: { text: "hello" }) params.expect(comments: [[:text]]) # => ActionController::ParameterMissing: param is missing or the value is empty or invalid: comments
expect is intended to protect against array tampering.
params = ActionController::Parameters.new(user: "hack") # The previous way of requiring and permitting parameters will error params.require(:user).permit(:name, pets: [:name]) # wrong # => NoMethodError: undefined method `permit' for an instance of String # similarly with nested parameters params = ActionController::Parameters.new(user: { name: "Martin", pets: { name: "hack" } }) user_params = params.require(:user).permit(:name, pets: [:name]) # wrong # user_params[:pets] is expected to be an array but is a hash
expect solves this by being more strict with types.
params = ActionController::Parameters.new(user: "hack") params.expect(user: [ :name, pets: [[:name]] ]) # => ActionController::ParameterMissing: param is missing or the value is empty or invalid: user # with nested parameters params = ActionController::Parameters.new(user: { name: "Martin", pets: { name: "hack" } }) user_params = params.expect(user: [:name, pets: [[:name]] ]) user_params[:pets] # => nil
As the examples show, expect requires the :user key, and any root keys similar to the .require.permit pattern. If multiple root keys are expected, they will all be required.
params = ActionController::Parameters.new(name: "Martin", pies: [{ type: "dessert", flavor: "pumpkin"}]) name, pies = params.expect(:name, pies: [[:type, :flavor]]) name # => "Martin" pies # => [#<ActionController::Parameters {"type"=>"dessert", "flavor"=>"pumpkin"} permitted: true>]
When called with a hash with multiple keys, expect will permit the parameters and require the keys in the order they are given in the hash, returning an array of the permitted parameters.
params = ActionController::Parameters.new(subject: { name: "Martin" }, object: { pie: "pumpkin" }) subject, object = params.expect(subject: [:name], object: [:pie]) subject # => #<ActionController::Parameters {"name"=>"Martin"} permitted: true> object # => #<ActionController::Parameters {"pie"=>"pumpkin"} permitted: true>
Besides being more strict about array vs hash params, expect uses permit internally, so it will behave similarly.
params = ActionController::Parameters.new({ person: { name: "Francesco", age: 22, pets: [{ name: "Purplish", category: "dogs" }] } }) permitted = params.expect(person: [ :name, { pets: [[:name]] } ]) permitted.permitted? # => true permitted[:name] # => "Francesco" permitted[:age] # => nil permitted[:pets][0][:name] # => "Purplish" permitted[:pets][0][:category] # => nil
An array of permitted scalars may be expected with the following:
params = ActionController::Parameters.new(tags: ["rails", "parameters"]) permitted = params.expect(tags: []) permitted # => ["rails", "parameters"] permitted.is_a?(Array) # => true permitted.size # => 2
Parameters
-
filtersrest
Source
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 772
def expect(*filters)
params = permit_filters(filters)
keys = filters.flatten.flat_map { |f| f.is_a?(Hash) ? f.keys : f }
values = params.require(keys)
values.size == 1 ? values.first : values
end
Defined in actionpack/lib/action_controller/metal/strong_parameters.rb line 772
· View on GitHub
· Improve this page
· Find usages on GitHub
Defined in ActionController::Parameters