class ActionController::Parameters - actionpack-4.2.4 Documentation

# class ActionController::Parameters

## Action Controller Parameters¶ ↑

Allows to choose which attributes should be whitelisted for mass updating and thus prevent accidentally exposing that which shouldn't be exposed. Provides two methods for this purpose: require and permit. The former is used to mark parameters as required. The latter is used to set the parameter as permitted and limit which attributes should be allowed for mass updating.

    params = ActionController::Parameters.new({
      person: {
        name: 'Francesco',
        age:  22,
        role: 'admin'
      }
    })

    permitted = params.require(:person).permit(:name, :age)
    permitted            # => {"name"=>"Francesco", "age"=>22}
    permitted.class      # => ActionController::Parameters
    permitted.permitted? # => true

    Person.first.update!(permitted)
    # => #<Person id: 1, name: "Francesco", age: 22, role: "user">

It provides two options that controls the top-level behavior of new instances:

- `permit_all_parameters` - If it's `true`, all the parameters will be permitted by default. The default is `false`.

- `action_on_unpermitted_parameters` - Allow to control the behavior when parameters that are not explicitly permitted are found. The values can be `:log` to write a message on the logger or `:raise` to raise ActionController::UnpermittedParameters exception. The default value is `:log` in test and development environments, `false` otherwise.

Examples:

    params = ActionController::Parameters.new
    params.permitted? # => false

    ActionController::Parameters.permit_all_parameters = true

    params = ActionController::Parameters.new
    params.permitted? # => true

    params = ActionController::Parameters.new(a: "123", b: "456")
    params.permit(:c)
    # => {}

    ActionController::Parameters.action_on_unpermitted_parameters = :raise

    params = ActionController::Parameters.new(a: "123", b: "456")
    params.permit(:c)
    # => ActionController::UnpermittedParameters: found unpermitted keys: a, b

Please note that these options *are not thread-safe*. In a multi-threaded environment they should only be set once at boot-time and never mutated at runtime.

`ActionController::Parameters` inherits from `ActiveSupport::HashWithIndifferentAccess`, this means that you can fetch values using either `:key` or `"key"`.

    params = ActionController::Parameters.new(key: 'value')
    params[:key]  # => "value"
    params["key"] # => "value"

### Constants

EMPTY_ARRAY
PERMITTED_SCALAR_TYPES

  This is a white list of permitted scalar types that includes the ones supported in XML and JSON requests.

  This list is in particular used to filter ordinary requests, String goes as first element to quickly short-circuit the common case.

  If you modify this collection please update the API of `permit` above.

### Public Class Methods

const_missing(const_name) click to toggle source
Calls superclass method

    # File lib/action_controller/metal/strong_parameters.rb, line 122
        def self.const_missing(const_name)
          super unless const_name == :NEVER_UNPERMITTED_PARAMS
          ActiveSupport::Deprecation.warn("        `ActionController::Parameters::NEVER_UNPERMITTED_PARAMS` has been deprecated.
            Use `ActionController::Parameters.always_permitted_parameters` instead.
    ".squish)

          always_permitted_parameters
        end

new(attributes = nil) click to toggle source

Returns a new instance of `ActionController::Parameters`. Also, sets the `permitted` attribute to the default value of `ActionController::Parameters.permit_all_parameters`.

    class Person < ActiveRecord::Base
    end

    params = ActionController::Parameters.new(name: 'Francesco')
    params.permitted?  # => false
    Person.new(params) # => ActiveModel::ForbiddenAttributesError

    ActionController::Parameters.permit_all_parameters = true

    params = ActionController::Parameters.new(name: 'Francesco')
    params.permitted?  # => true
    Person.new(params) # => #<Person id: nil, name: "Francesco">

Calls superclass method

    # File lib/action_controller/metal/strong_parameters.rb, line 148
    def initialize(attributes = nil)
      super(attributes)
      @permitted = self.class.permit_all_parameters
    end

### Public Instance Methods

[](key) click to toggle source

Returns a parameter for the given `key`. If not found, returns `nil`.

    params = ActionController::Parameters.new(person: { name: 'Francesco' })
    params[:person] # => {"name"=>"Francesco"}
    params[:none]   # => nil

Calls superclass method

    # File lib/action_controller/metal/strong_parameters.rb, line 350
    def [](key)
      convert_hashes_to_parameters(key, super)
    end

converted_arrays() click to toggle source

Attribute that keeps track of converted arrays, if any, to avoid double looping in the common use case permit + mass-assignment. Defined in a method to instantiate it only if needed.

Testing membership still loops, but it's going to be faster than our own loop that converts values. Also, we are not going to build a new array object per fetch.

    # File lib/action_controller/metal/strong_parameters.rb, line 197
    def converted_arrays
      @converted_arrays ||= Set.new
    end

delete(key, &block) click to toggle source

Deletes and returns a key-value pair from `Parameters` whose key is equal to key. If the key is not found, returns the default value. If the optional code block is given and the key is not found, pass in the key and return the result of block.

Calls superclass method

    # File lib/action_controller/metal/strong_parameters.rb, line 420
    def delete(key, &block)
      convert_hashes_to_parameters(key, super, false)
    end

dup() click to toggle source

Returns an exact copy of the `ActionController::Parameters` instance. `permitted` state is kept on the duped object.

    params = ActionController::Parameters.new(a: 1)
    params.permit!
    params.permitted?        # => true
    copy_params = params.dup # => {"a"=>1}
    copy_params.permitted?   # => true

Calls superclass method

    # File lib/action_controller/metal/strong_parameters.rb, line 437
    def dup
      super.tap do |duplicate|
        duplicate.permitted = @permitted
      end
    end

each(&block)
Alias for: each_pair
each_pair(&block) click to toggle source

Convert all hashes in values into parameters, then yield each pair like the same way as `Hash#each_pair`

Calls superclass method

    # File lib/action_controller/metal/strong_parameters.rb, line 180
    def each_pair(&block)
      super do |key, value|
        convert_hashes_to_parameters(key, value)
      end

      super
    end

Also aliased as: each
extract!(*keys) click to toggle source

Removes and returns the key/value pairs matching the given keys.

    params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
    params.extract!(:a, :b) # => {"a"=>1, "b"=>2}
    params                  # => {"c"=>3}

Calls superclass method

    # File lib/action_controller/metal/strong_parameters.rb, line 387
    def extract!(*keys)
      new_instance_with_inherited_permitted_status(super)
    end

fetch(key, *args) click to toggle source

Returns a parameter for the given `key`. If the `key` can't be found, there are several options: With no other arguments, it will raise an `ActionController::ParameterMissing` error; if more arguments are given, then that will be returned; if a block is given, then that will be run and its result returned.

    params = ActionController::Parameters.new(person: { name: 'Francesco' })
    params.fetch(:person)               # => {"name"=>"Francesco"}
    params.fetch(:none)                 # => ActionController::ParameterMissing: param not found: none
    params.fetch(:none, 'Francesco')    # => "Francesco"
    params.fetch(:none) { 'Francesco' } # => "Francesco"

Calls superclass method

    # File lib/action_controller/metal/strong_parameters.rb, line 365
    def fetch(key, *args)
      convert_hashes_to_parameters(key, super, false)
    rescue KeyError
      raise ActionController::ParameterMissing.new(key)
    end

permit(*filters) click to toggle source

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(user: { name: 'Francesco', age: 22, role: 'admin' })
    permitted = params.require(:user).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 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: [])

You can also use `permit` on nested parameters, like:

    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

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 whitelisted.

    params = ActionController::Parameters.new({
      person: {
        contact: {
          email: 'none@test.com',
          phone: '555-1234'
        }
      }
    })

    params.require(:person).permit(:contact)
    # => {}

    params.require(:person).permit(contact: :phone)
    # => {"contact"=>{"phone"=>"555-1234"}}

    params.require(:person).permit(contact: [ :email, :phone ])
    # => {"contact"=>{"email"=>"none@test.com", "phone"=>"555-1234"}}

    # File lib/action_controller/metal/strong_parameters.rb, line 327
    def permit(*filters)
      params = self.class.new

      filters.flatten.each do |filter|
        case filter
        when Symbol, String
          permitted_scalar_filter(params, filter)
        when Hash then
          hash_filter(params, filter)
        end
      end

      unpermitted_parameters!(params) if self.class.action_on_unpermitted_parameters

      params.permit!
    end

permit!() click to toggle source

Sets the `permitted` attribute to `true`. This can be used to pass mass assignment. Returns `self`.

    class Person < ActiveRecord::Base
    end

    params = ActionController::Parameters.new(name: 'Francesco')
    params.permitted?  # => false
    Person.new(params) # => ActiveModel::ForbiddenAttributesError
    params.permit!
    params.permitted?  # => true
    Person.new(params) # => #<Person id: nil, name: "Francesco">

    # File lib/action_controller/metal/strong_parameters.rb, line 223
    def permit!
      each_pair do |key, value|
        Array.wrap(value).each do |v|
          v.permit! if v.respond_to? :permit!
        end
      end

      @permitted = true
      self
    end

permitted?() click to toggle source

Returns `true` if the parameter is permitted, `false` otherwise.

    params = ActionController::Parameters.new
    params.permitted? # => false
    params.permit!
    params.permitted? # => true

    # File lib/action_controller/metal/strong_parameters.rb, line 207
    def permitted?
      @permitted
    end

require(key) click to toggle source

Ensures that a parameter is present. If it's present, returns the parameter at the given `key`, otherwise raises an `ActionController::ParameterMissing` error.

    ActionController::Parameters.new(person: { name: 'Francesco' }).require(:person)
    # => {"name"=>"Francesco"}

    ActionController::Parameters.new(person: nil).require(:person)
    # => ActionController::ParameterMissing: param not found: person

    ActionController::Parameters.new(person: {}).require(:person)
    # => ActionController::ParameterMissing: param not found: person

    # File lib/action_controller/metal/strong_parameters.rb, line 246
    def require(key)
      value = self[key]
      if value.present? || value == false
        value
      else
        raise ParameterMissing.new(key)
      end
    end

Also aliased as: required
required(key)

Alias of require.

Alias for: require
select!(&block) click to toggle source

Equivalent to Hash#keep_if, but returns nil if no changes were made.

Calls superclass method

    # File lib/action_controller/metal/strong_parameters.rb, line 425
    def select!(&block)
      convert_value_to_parameters(super)
    end

slice(*keys) click to toggle source

Returns a new `ActionController::Parameters` instance that includes only the given `keys`. If the given `keys` don't exist, returns an empty hash.

    params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
    params.slice(:a, :b) # => {"a"=>1, "b"=>2}
    params.slice(:d)     # => {}

Calls superclass method

    # File lib/action_controller/metal/strong_parameters.rb, line 378
    def slice(*keys)
      new_instance_with_inherited_permitted_status(super)
    end

to_h() click to toggle source

Returns a safe `Hash` representation of this parameter with all unpermitted keys removed.

    params = ActionController::Parameters.new({
      name: 'Senjougahara Hitagi',
      oddity: 'Heavy stone crab'
    })
    params.to_h # => {}

    safe_params = params.permit(:name)
    safe_params.to_h # => {"name"=>"Senjougahara Hitagi"}

    # File lib/action_controller/metal/strong_parameters.rb, line 164
    def to_h
      if permitted?
        to_hash
      else
        slice(*self.class.always_permitted_parameters).permit!.to_h
      end
    end

to_unsafe_h() click to toggle source

Returns an unsafe, unfiltered `Hash` representation of this parameter.

    # File lib/action_controller/metal/strong_parameters.rb, line 173
    def to_unsafe_h
      to_hash
    end

Also aliased as: to_unsafe_hash
to_unsafe_hash()
Alias for: to_unsafe_h
transform_values() click to toggle source

Returns a new `ActionController::Parameters` with the results of running `block` once for every value. The keys are unchanged.

    params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
    params.transform_values { |x| x * 2 }
    # => {"a"=>2, "b"=>4, "c"=>6}

Calls superclass method

    # File lib/action_controller/metal/strong_parameters.rb, line 397
    def transform_values
      if block_given?
        new_instance_with_inherited_permitted_status(super)
      else
        super
      end
    end

### Protected Instance Methods

permitted=(new_permitted) click to toggle source

    # File lib/action_controller/metal/strong_parameters.rb, line 444
    def permitted=(new_permitted)
      @permitted = new_permitted
    end

### Private Instance Methods

array_of_permitted_scalars?(value) click to toggle source

    # File lib/action_controller/metal/strong_parameters.rb, line 549
    def array_of_permitted_scalars?(value)
      if value.is_a?(Array)
        value.all? {|element| permitted_scalar?(element)}
      end
    end

array_of_permitted_scalars_filter(params, key) click to toggle source

    # File lib/action_controller/metal/strong_parameters.rb, line 555
    def array_of_permitted_scalars_filter(params, key)
      if has_key?(key) && array_of_permitted_scalars?(self[key])
        params[key] = self[key]
      end
    end

convert_hashes_to_parameters(key, value, assign_if_converted=true) click to toggle source

    # File lib/action_controller/metal/strong_parameters.rb, line 455
    def convert_hashes_to_parameters(key, value, assign_if_converted=true)
      converted = convert_value_to_parameters(value)
      self[key] = converted if assign_if_converted && !converted.equal?(value)
      converted
    end

convert_value_to_parameters(value) click to toggle source

    # File lib/action_controller/metal/strong_parameters.rb, line 461
    def convert_value_to_parameters(value)
      if value.is_a?(Array) && !converted_arrays.member?(value)
        converted = value.map { |_| convert_value_to_parameters(_) }
        converted_arrays << converted
        converted
      elsif value.is_a?(Parameters) || !value.is_a?(Hash)
        value
      else
        self.class.new(value)
      end
    end

each_element(object) { |el| ... } click to toggle source

    # File lib/action_controller/metal/strong_parameters.rb, line 473
    def each_element(object)
      if object.is_a?(Array)
        object.map { |el| yield el }.compact
      elsif fields_for_style?(object)
        hash = object.class.new
        object.each { |k,v| hash[k] = yield v }
        hash
      else
        yield object
      end
    end

fields_for_style?(object) click to toggle source

    # File lib/action_controller/metal/strong_parameters.rb, line 485
    def fields_for_style?(object)
      object.is_a?(Hash) && object.all? { |k, v| k =~ /\A-?\d+\z/ && v.is_a?(Hash) }
    end

hash_filter(params, filter) click to toggle source

    # File lib/action_controller/metal/strong_parameters.rb, line 562
    def hash_filter(params, filter)
      filter = filter.with_indifferent_access

      # Slicing filters out non-declared keys.
      slice(*filter.keys).each do |key, value|
        next unless value

        if filter[key] == EMPTY_ARRAY
          # Declaration { comment_ids: [] }.
          array_of_permitted_scalars_filter(params, key)
        else
          # Declaration { user: :name } or { user: [:name, :age, { address: ... }] }.
          params[key] = each_element(value) do |element|
            if element.is_a?(Hash)
              element = self.class.new(element) unless element.respond_to?(:permit)
              element.permit(*Array.wrap(filter[key]))
            end
          end
        end
      end
    end

new_instance_with_inherited_permitted_status(hash) click to toggle source

    # File lib/action_controller/metal/strong_parameters.rb, line 449
    def new_instance_with_inherited_permitted_status(hash)
      self.class.new(hash).tap do |new_instance|
        new_instance.permitted = @permitted
      end
    end

permitted_scalar?(value) click to toggle source

    # File lib/action_controller/metal/strong_parameters.rb, line 533
    def permitted_scalar?(value)
      PERMITTED_SCALAR_TYPES.any? {|type| value.is_a?(type)}
    end

permitted_scalar_filter(params, key) click to toggle source

    # File lib/action_controller/metal/strong_parameters.rb, line 537
    def permitted_scalar_filter(params, key)
      if has_key?(key) && permitted_scalar?(self[key])
        params[key] = self[key]
      end

      keys.grep(/\A#{Regexp.escape(key)}\(\d+[if]?\)\z/) do |k|
        if permitted_scalar?(self[k])
          params[k] = self[k]
        end
      end
    end

unpermitted_keys(params) click to toggle source

    # File lib/action_controller/metal/strong_parameters.rb, line 502
    def unpermitted_keys(params)
      self.keys - params.keys - self.always_permitted_parameters
    end

unpermitted_parameters!(params) click to toggle source

    # File lib/action_controller/metal/strong_parameters.rb, line 489
    def unpermitted_parameters!(params)
      unpermitted_keys = unpermitted_keys(params)
      if unpermitted_keys.any?
        case self.class.action_on_unpermitted_parameters
        when :log
          name = "unpermitted_parameters.action_controller"
          ActiveSupport::Notifications.instrument(name, keys: unpermitted_keys)
        when :raise
          raise ActionController::UnpermittedParameters.new(unpermitted_keys)
        end
      end
    end