Method: ActionController::Parameters#permit

Defined in:
lib/action_controller/metal/strong_parameters.rb

#permit(*filters) ⇒ Object

Returns a new ActionController::Parameters instance that includes only the given filters and sets the permitted attribute for the object to true. This is useful for limiting which attributes should be allowed for mass updating.

params = ActionController::Parameters.new(name: "Francesco", age: 22, role: "admin")
permitted = params.permit(:name, :age)
permitted.permitted?      # => true
permitted.has_key?(:name) # => true
permitted.has_key?(:age)  # => true
permitted.has_key?(:role) # => false

Only permitted scalars pass the filter. For example, given

params.permit(:name)

:name passes if it is a key of params whose associated value is of type String, Symbol, NilClass, Numeric, TrueClass, FalseClass, Date, Time, DateTime, StringIO, IO, ActionDispatch::Http::UploadedFile or Rack::Test::UploadedFile. Otherwise, the key :name is filtered out.

You may declare that the parameter should be an array of permitted scalars by mapping it to an empty array:

params = ActionController::Parameters.new(tags: ["rails", "parameters"])
params.permit(tags: [])

Sometimes it is not possible or convenient to declare the valid keys of a hash parameter or its internal structure. Just map to an empty hash:

params.permit(preferences: {})

Be careful because this opens the door to arbitrary input. In this case, permit ensures values in the returned structure are permitted scalars and filters out anything else.

You can also use permit on nested parameters:

params = ActionController::Parameters.new({
  person: {
    name: "Francesco",
    age:  22,
    pets: [{
      name: "Purplish",
      category: "dogs"
    }]
  }
})

permitted = params.permit(person: [ :name, { pets: :name } ])
permitted.permitted?                    # => true
permitted[:person][:name]               # => "Francesco"
permitted[:person][:age]                # => nil
permitted[:person][:pets][0][:name]     # => "Purplish"
permitted[:person][:pets][0][:category] # => nil

This has the added benefit of rejecting user-modified inputs that send a string when a hash is expected.

When followed by require, you can both filter and require parameters following the typical pattern of a Rails form. The expect method was made specifically for this use case and is the recommended way to require and permit parameters.

permitted = params.expect(person: [:name, :age])

When using permit and require separately, pay careful attention to the order of the method calls.

params = ActionController::Parameters.new(person: { name: "Martin", age: 40, role: "admin" })
permitted = params.permit(person: [:name, :age]).require(:person) # correct

When require is used first, it is possible for users of your application to trigger a NoMethodError when the user, for example, sends a string for :person.

params = ActionController::Parameters.new(person: "tampered")
permitted = params.require(:person).permit(:name, :age) # not recommended
# => NoMethodError: undefined method `permit' for an instance of String

Note that if you use permit in a key that points to a hash, it won’t allow all the hash. You also need to specify which attributes inside the hash should be permitted.

params = ActionController::Parameters.new({
  person: {
    contact: {
      email: "[email protected]",
      phone: "555-1234"
    }
  }
})

params.permit(person: :contact).require(:person)
# => ActionController::ParameterMissing: param is missing or the value is empty or invalid: person

params.permit(person: { contact: :phone }).require(:person)
# => #<ActionController::Parameters {"contact"=>#<ActionController::Parameters {"phone"=>"555-1234"} permitted: true>} permitted: true>

params.permit(person: { contact: [ :email, :phone ] }).require(:person)
# => #<ActionController::Parameters {"contact"=>#<ActionController::Parameters {"email"=>"[email protected]", "phone"=>"555-1234"} permitted: true>} permitted: true>

If your parameters specify multiple parameters indexed by a number, you can permit each set of parameters under the numeric key to be the same using the same syntax as permitting a single item.

params = ActionController::Parameters.new({
  person: {
    '0': {
      email: "[email protected]",
      phone: "555-1234"
    },
    '1': {
      email: "[email protected]",
      phone: "555-6789"
    },
  }
})
params.permit(person: [:email]).to_h
# => {"person"=>{"0"=>{"email"=>"[email protected]"}, "1"=>{"email"=>"[email protected]"}}}

If you want to specify what keys you want from each numeric key, you can instead specify each one individually

params = ActionController::Parameters.new({
  person: {
    '0': {
      email: "[email protected]",
      phone: "555-1234"
    },
    '1': {
      email: "[email protected]",
      phone: "555-6789"
    },
  }
})
params.permit(person: { '0': [:email], '1': [:phone]}).to_h
# => {"person"=>{"0"=>{"email"=>"[email protected]"}, "1"=>{"phone"=>"555-6789"}}}


668
669
670
# File 'lib/action_controller/metal/strong_parameters.rb', line 668

def permit(*filters)
  permit_filters(filters, on_unpermitted: self.class.action_on_unpermitted_parameters, explicit_arrays: false)
end