197

All the examples of strong parameters in Rails 4 docs use

params.require(:person).permit(:name, :age)

Could someone please deconstruct and explain what is occurring with require and permit here?

Soviut
  • 88,194
  • 49
  • 192
  • 260
Erik Trautman
  • 5,883
  • 2
  • 27
  • 35

3 Answers3

267

The params in a controller looks like a Hash, but it's actually an instance of ActionController::Parameters, which provides several methods such as require and permit.

The require method ensures that a specific parameter is present, and if it's not provided, the require method throws an error. It returns an instance of ActionController::Parameters for the key passed into require.

The permit method returns a copy of the parameters object, returning only the permitted keys and values. When creating a new ActiveRecord model, only the permitted attributes are passed into the model.

It looks a lot like the whitelisting that was formerly included in ActiveRecord models, but it makes more sense for it to be in the controller.

kingsfoil
  • 3,795
  • 7
  • 32
  • 56
fivedigit
  • 18,464
  • 6
  • 54
  • 58
  • 53
    The description of permit is a bit off: permit returns another hash that contains only the permitted key AND (this is critical) will respond with `true` to the `permitted?` method. By default, an instance of the `ActionController::Parameters` class will return `false` for `permitted?` Responding `true` to `permitted?` means the parameter object can be used in mass assignment; else the app will throw a ForbiddenAttributes error. – sameers Nov 13 '13 at 18:05
  • 5
    Does chaining `permit` on `require` also permit and include the required parameters in the returned object? – Dennis Apr 06 '16 at 14:49
  • 2
    I find the naming unfortunate, as require does a lot more than making a permitted parameter required. Using params.permit(:person, :name, :age) does not work, and generates errors like "Unpermitted parameters: :utf8" for a typical form. – Damien Aug 30 '18 at 13:03
23

Think of require as validation and permit as filtering.

  • require will return the params under the given key if present, or raise
  • permit will return the params filtered on the given keys*

Examples based on https://apidock.com/rails/ActionController/Parameters/permit

>> params = ActionController::Parameters.new(user: { name: "Francesco", age: 22, role: "admin" })
{
    "user" => {
        "name" => "Francesco",
         "age" => 22,
        "role" => "admin"
    }
}

>> params.require(:user).permit(:name, :age)
Unpermitted parameter: role
{
    "name" => "Francesco",
     "age" => 22
}

>> params.require(:user)
{
    "name" => "Francesco",
     "age" => 22,
    "role" => "admin"
}

>> params.require(:user).permit(:foo)
Unpermitted parameters: name, age, role
{}

>> params.require(:person)
ActionController::ParameterMissing: param is missing or the value is empty: person

>> params.permit(:user)
Unpermitted parameter: user
{}

* Note that permit only allows certain scalars to pass the filter, as seen in the last example. The associated data must be of type String, Symbol, NilClass, Numeric, TrueClass, FalseClass, Date, Time, DateTime, StringIO, IO, ActionDispatch::Http::UploadedFile or Rack::Test::UploadedFile. Everything else, including containers like Array and Hash, are filtered out.

Dennis
  • 56,821
  • 26
  • 143
  • 139
11

To be more precise, when you create for eg. doing .new(...), there must be :person hash indicated by require and the person hash will only accept :name and :age indicated by permit.

Example:

.new(person: { name: "Bhojendra", age: 32 }) // okay
.new(person: { name: "Rauniyar" }) // okay
.new(person: { name: "Bhojendra", other: 'asdf' }) // not okay, other not permitted
.new(person: { full_name: "Bhojendra Rauniyar" }) // not okay, full_name not permitted
.new(detail: { name: "Bhojendra", age: 32 }) // not okay, must be person
Harry Wood
  • 2,220
  • 2
  • 24
  • 46
Bhojendra Rauniyar
  • 83,432
  • 35
  • 168
  • 231