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:

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/backports/action_controller/metal/strong_parameters.rb
124       def self.const_missing(const_name)
125         super unless const_name == :NEVER_UNPERMITTED_PARAMS
126         ActiveSupport::Deprecation.warn(<<-MSG.squish)
127           `ActionController::Parameters::NEVER_UNPERMITTED_PARAMS` has been deprecated.
128           Use `ActionController::Parameters.always_permitted_parameters` instead.
129         MSG
130 
131         always_permitted_parameters
132       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/backports/action_controller/metal/strong_parameters.rb
150 def initialize(attributes = nil)
151   super(attributes)
152   @permitted = self.class.permit_all_parameters
153 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/backports/action_controller/metal/strong_parameters.rb
352 def [](key)
353   convert_hashes_to_parameters(key, super)
354 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/backports/action_controller/metal/strong_parameters.rb
199 def converted_arrays
200   @converted_arrays ||= Set.new
201 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/backports/action_controller/metal/strong_parameters.rb
422 def delete(key, &block)
423   convert_hashes_to_parameters(key, super, false)
424 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/backports/action_controller/metal/strong_parameters.rb
439 def dup
440   super.tap do |duplicate|
441     duplicate.permitted = @permitted
442   end
443 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/backports/action_controller/metal/strong_parameters.rb
182 def each_pair(&block)
183   super do |key, value|
184     convert_hashes_to_parameters(key, value)
185   end
186 
187   super
188 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/backports/action_controller/metal/strong_parameters.rb
389 def extract!(*keys)
390   new_instance_with_inherited_permitted_status(super)
391 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/backports/action_controller/metal/strong_parameters.rb
367 def fetch(key, *args)
368   convert_hashes_to_parameters(key, super, false)
369 rescue KeyError
370   raise ActionController::ParameterMissing.new(key)
371 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/backports/action_controller/metal/strong_parameters.rb
329 def permit(*filters)
330   params = self.class.new
331 
332   filters.flatten.each do |filter|
333     case filter
334     when Symbol, String
335       permitted_scalar_filter(params, filter)
336     when Hash then
337       hash_filter(params, filter)
338     end
339   end
340 
341   unpermitted_parameters!(params) if self.class.action_on_unpermitted_parameters
342 
343   params.permit!
344 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/backports/action_controller/metal/strong_parameters.rb
225 def permit!
226   each_pair do |key, value|
227     Array.wrap(value).each do |v|
228       v.permit! if v.respond_to? :permit!
229     end
230   end
231 
232   @permitted = true
233   self
234 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/backports/action_controller/metal/strong_parameters.rb
209 def permitted?
210   @permitted
211 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/backports/action_controller/metal/strong_parameters.rb
248 def require(key)
249   value = self[key]
250   if value.present? || value == false
251     value
252   else
253     raise ParameterMissing.new(key)
254   end
255 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/backports/action_controller/metal/strong_parameters.rb
427 def select!(&block)
428   convert_value_to_parameters(super)
429 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/backports/action_controller/metal/strong_parameters.rb
380 def slice(*keys)
381   new_instance_with_inherited_permitted_status(super)
382 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/backports/action_controller/metal/strong_parameters.rb
166 def to_h
167   if permitted?
168     to_hash
169   else
170     slice(*self.class.always_permitted_parameters).permit!.to_h
171   end
172 end
to_unsafe_h() click to toggle source

Returns an unsafe, unfiltered Hash representation of this parameter.

    # File lib/backports/action_controller/metal/strong_parameters.rb
175 def to_unsafe_h
176   to_hash
177 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/backports/action_controller/metal/strong_parameters.rb
399 def transform_values
400   if block_given?
401     new_instance_with_inherited_permitted_status(super)
402   else
403     super
404   end
405 end

Protected Instance Methods

permitted=(new_permitted) click to toggle source
    # File lib/backports/action_controller/metal/strong_parameters.rb
446 def permitted=(new_permitted)
447   @permitted = new_permitted
448 end

Private Instance Methods

array_of_permitted_scalars?(value) click to toggle source
    # File lib/backports/action_controller/metal/strong_parameters.rb
551 def array_of_permitted_scalars?(value)
552   if value.is_a?(Array)
553     value.all? {|element| permitted_scalar?(element)}
554   end
555 end
array_of_permitted_scalars_filter(params, key) click to toggle source
    # File lib/backports/action_controller/metal/strong_parameters.rb
557 def array_of_permitted_scalars_filter(params, key)
558   if has_key?(key) && array_of_permitted_scalars?(self[key])
559     params[key] = self[key]
560   end
561 end
convert_hashes_to_parameters(key, value, assign_if_converted=true) click to toggle source
    # File lib/backports/action_controller/metal/strong_parameters.rb
457 def convert_hashes_to_parameters(key, value, assign_if_converted=true)
458   converted = convert_value_to_parameters(value)
459   self[key] = converted if assign_if_converted && !converted.equal?(value)
460   converted
461 end
convert_value_to_parameters(value) click to toggle source
    # File lib/backports/action_controller/metal/strong_parameters.rb
463 def convert_value_to_parameters(value)
464   if value.is_a?(Array) && !converted_arrays.member?(value)
465     converted = value.map { |_| convert_value_to_parameters(_) }
466     converted_arrays << converted
467     converted
468   elsif value.is_a?(Parameters) || !value.is_a?(Hash)
469     value
470   else
471     self.class.new(value)
472   end
473 end
each_element(object) { |el| ... } click to toggle source
    # File lib/backports/action_controller/metal/strong_parameters.rb
475 def each_element(object)
476   if object.is_a?(Array)
477     object.map { |el| yield el }.compact
478   elsif fields_for_style?(object)
479     hash = object.class.new
480     object.each { |k,v| hash[k] = yield v }
481     hash
482   else
483     yield object
484   end
485 end
fields_for_style?(object) click to toggle source
    # File lib/backports/action_controller/metal/strong_parameters.rb
487 def fields_for_style?(object)
488   object.is_a?(Hash) && object.all? { |k, v| k =~ /\A-?\d+\z/ && v.is_a?(Hash) }
489 end
hash_filter(params, filter) click to toggle source
    # File lib/backports/action_controller/metal/strong_parameters.rb
564 def hash_filter(params, filter)
565   filter = filter.with_indifferent_access
566 
567   # Slicing filters out non-declared keys.
568   slice(*filter.keys).each do |key, value|
569     next unless value
570 
571     if filter[key] == EMPTY_ARRAY
572       # Declaration { comment_ids: [] }.
573       array_of_permitted_scalars_filter(params, key)
574     else
575       # Declaration { user: :name } or { user: [:name, :age, { address: ... }] }.
576       params[key] = each_element(value) do |element|
577         if element.is_a?(Hash)
578           element = self.class.new(element) unless element.respond_to?(:permit)
579           element.permit(*Array.wrap(filter[key]))
580         end
581       end
582     end
583   end
584 end
new_instance_with_inherited_permitted_status(hash) click to toggle source
    # File lib/backports/action_controller/metal/strong_parameters.rb
451 def new_instance_with_inherited_permitted_status(hash)
452   self.class.new(hash).tap do |new_instance|
453     new_instance.permitted = @permitted
454   end
455 end
permitted_scalar?(value) click to toggle source
    # File lib/backports/action_controller/metal/strong_parameters.rb
535 def permitted_scalar?(value)
536   PERMITTED_SCALAR_TYPES.any? {|type| value.is_a?(type)}
537 end
permitted_scalar_filter(params, key) click to toggle source
    # File lib/backports/action_controller/metal/strong_parameters.rb
539 def permitted_scalar_filter(params, key)
540   if has_key?(key) && permitted_scalar?(self[key])
541     params[key] = self[key]
542   end
543 
544   keys.grep(/\A#{Regexp.escape(key)}\(\d+[if]?\)\z/) do |k|
545     if permitted_scalar?(self[k])
546       params[k] = self[k]
547     end
548   end
549 end
unpermitted_keys(params) click to toggle source
    # File lib/backports/action_controller/metal/strong_parameters.rb
504 def unpermitted_keys(params)
505   self.keys - params.keys - self.always_permitted_parameters
506 end
unpermitted_parameters!(params) click to toggle source
    # File lib/backports/action_controller/metal/strong_parameters.rb
491 def unpermitted_parameters!(params)
492   unpermitted_keys = unpermitted_keys(params)
493   if unpermitted_keys.any?
494     case self.class.action_on_unpermitted_parameters
495     when :log
496       name = "unpermitted_parameters.action_controller"
497       ActiveSupport::Notifications.instrument(name, keys: unpermitted_keys)
498     when :raise
499       raise ActionController::UnpermittedParameters.new(unpermitted_keys)
500     end
501   end
502 end