class ActionController::Parameters
Параметры Action Controller
Позволяет выбрать атрибуты, которые следует разрешить для массового обновления, предотвращая случайное раскрытие конфиденциальных данных. Для этого предоставляются два метода: require и permit. Первый используется для обозначения параметров как обязательных. Второй — для разрешения параметров и ограничения атрибутов, разрешенных для массового обновления.
params = ActionController::Parameters.new({
person: {
name: "Francesco",
age: 22,
role: "admin"
}
})
permitted = params.require(:person).permit(:name, :age)
permitted # => <ActionController::Parameters {"name"=>"Francesco", "age"=>22} permitted: true>
permitted.permitted? # => true
Person.first.update!(permitted)
# => #<Person id: 1, name: "Francesco", age: 22, role: "user">
Он предоставляет две опции, которые контролируют поведение новых экземпляров:
-
permit_all_parameters— Если этоtrue, все параметры будут разрешены по умолчанию. По умолчаниюfalse. -
action_on_unpermitted_parameters— Позволяет контролировать поведение при обнаружении параметров, не разрешенных явно. Значения могут быть:logдля записи сообщения в логгер или:raiseдля повышения исключения ActionController::UnpermittedParameters. Значение по умолчанию —:logв тестовых и отладочных средах,falseв остальных случаях.
Примеры:
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 {} permitted: true>
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
Обратите внимание, что эти параметры *не потокобезопасны*. В многопоточной среде их следует устанавливать один раз во время запуска и никогда не изменять во время выполнения.
Вы можете получить значения ActionController::Parameters с помощью :key или "key".
params = ActionController::Parameters.new(key: "value") params[:key] # => "value" params["key"] # => "value"
Константы
- EMPTY_ARRAY
- PERMITTED_SCALAR_TYPES
-
Это список разрешенных скалярных типов, включающих типы, поддерживаемые запросами XML и JSON.
Этот список используется, в частности, для фильтрации обычных запросов; String стоит первым элементом, чтобы быстро исключить распространенный случай.
Если вы измените этот список, обновите API
permitвыше.
Атрибуты
Публичные методы класса
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 233
def initialize(parameters = {})
@parameters = parameters.with_indifferent_access
@permitted = self.class.permit_all_parameters
end Возвращает новый экземпляр ActionController::Parameters. Также устанавливает атрибут permitted в значение по умолчанию 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">
Публичные методы экземпляров
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 240
def ==(other)
if other.respond_to?(:permitted?)
self.permitted? == other.permitted? && self.parameters == other.parameters
elsif other.is_a?(Hash)
ActiveSupport::Deprecation.warn " Comparing equality between `ActionController::Parameters` and a
`Hash` is deprecated and will be removed in Rails 5.1. Please only do
comparisons between instances of `ActionController::Parameters`. If
you need to compare to a hash, first convert it using
`ActionController::Parameters#new`.
".squish
@parameters == other.with_indifferent_access
else
@parameters == other
end
end Возвращает true, если другой объект Parameters содержит то же содержимое и разрешающий флаг.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 561 def [](key) convert_hashes_to_parameters(key, @parameters[key]) end
Возвращает параметр для данного key. Если не найдено, возвращает nil.
params = ActionController::Parameters.new(person: { name: "Francesco" })
params[:person] # => <ActionController::Parameters {"name"=>"Francesco"} permitted: false>
params[:none] # => nil
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 567 def []=(key, value) @parameters[key] = value end
Присваивает значение данному key. Указанный ключ может быть отфильтрован при вызове permit.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 134
Возвращает хеш, который может использоваться как JSON-представление параметров.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 369 def converted_arrays @converted_arrays ||= Set.new end
Атрибут, который отслеживает преобразованные массивы (если таковые имеются), чтобы избежать двойного циклирования в общем случае с разрешением + массовым присваиванием. Определён в методе для инициализации только при необходимости.
Тестирование членства всё ещё использует циклы, но это будет быстрее, чем собственный цикл преобразования значений. Кроме того, мы не будем создавать новый объект массива при каждом получении.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 804
def deep_dup
self.class.new(@parameters.deep_dup).tap do |duplicate|
duplicate.permitted = @permitted
end
end Возвращает дубликат объекта, включая все параметры.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 692 def delete(key, &block) convert_value_to_parameters(@parameters.delete(key, &block)) end
Удаляет и возвращает пару ключ-значение из Parameters, ключ которой равен ключу. Если ключ не найден, возвращает значение по умолчанию. Если задан необязательный блок кода и ключ не найден, передаёт ключ и возвращает результат блока.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 604 def dig(*keys) convert_value_to_parameters(@parameters.dig(*keys)) end
Извлекает вложенный параметр из заданного keys путём вызова dig на каждом шаге. Возвращает nil , если любой промежуточный шаг nil.
params = ::new(foo: { bar: { baz: 1 } }) params.dig(:foo, :bar, :baz) # => 1 params.dig(:foo, :zot, :xyz) # => nil
params2 = ::new(foo: [10, 11, 12]) params2.dig(:foo, 1) # => 11
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 355
def each_pair(&block)
@parameters.each_pair do |key, value|
yield key, convert_hashes_to_parameters(key, value)
end
end Преобразует все хеши в значения в параметры, затем передает каждую пару таким же образом, как Hash#each_pair
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 142
Возвращает true, если объект не содержит пар ключ/значение.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 633 def except(*keys) new_instance_with_inherited_permitted_status(@parameters.except(*keys)) end
Возвращает новый экземпляр ActionController::Parameters , который фильтрует заданные keys.
params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
params.except(:a, :b) # => <ActionController::Parameters {"c"=>3} permitted: false>
params.except(:d) # => <ActionController::Parameters {"a"=>1, "b"=>2, "c"=>3} permitted: false>
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 642 def extract!(*keys) new_instance_with_inherited_permitted_status(@parameters.extract!(*keys)) end
Удаляет и возвращает пары ключ/значение, соответствующие заданным ключам.
params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
params.extract!(:a, :b) # => <ActionController::Parameters {"a"=>1, "b"=>2} permitted: false>
params # => <ActionController::Parameters {"c"=>3} permitted: false>
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 582
def fetch(key, *args)
convert_value_to_parameters(
@parameters.fetch(key) {
if block_given?
yield
else
args.fetch(0) { raise ActionController::ParameterMissing.new(key) }
end
}
)
end Возвращает параметр для данного key. Если key не найден, существует несколько вариантов: без других аргументов он вызовет ошибку ActionController::ParameterMissing; если задано несколько аргументов, то они будут возвращены; если задан блок, то он будет выполнен, а его результат возвращён.
params = ActionController::Parameters.new(person: { name: "Francesco" })
params.fetch(:person) # => <ActionController::Parameters {"name"=>"Francesco"} permitted: false>
params.fetch(:none) # => ActionController::ParameterMissing: param is missing or the value is empty: none
params.fetch(:none, "Francesco") # => "Francesco"
params.fetch(:none) { "Francesco" } # => "Francesco"
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 150
Возвращает true, если указанный ключ присутствует в параметрах.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 158
Возвращает true, если заданное значение присутствует для какого-либо ключа в параметрах.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 166
Возвращает true, если указанный ключ присутствует в параметрах.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 750
def inspect
"<#{self.class} #{@parameters} permitted: #{@permitted}>"
end # File actionpack/lib/action_controller/metal/strong_parameters.rb, line 174
Возвращает true, если указанный ключ присутствует в параметрах.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 182
Возвращает новый массив ключей параметров.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 730
def merge(other_hash)
new_instance_with_inherited_permitted_status(
@parameters.merge(other_hash.to_h)
)
end Возвращает новый ActionController::Parameters со всеми ключами из other_hash , которые объединяются в текущий хеш.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 738 def merge!(other_hash) @parameters.merge!(other_hash.to_h) self end
Возвращает текущий экземпляр ActionController::Parameters , который other_hash объединяет в текущий хеш.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 781
def method_missing(method_sym, *args, &block)
if @parameters.respond_to?(method_sym)
message = " Method #{method_sym} is deprecated and will be removed in Rails 5.1,
as `ActionController::Parameters` no longer inherits from
hash. Using this deprecated behavior exposes potential security
problems. If you continue to use this method you may be creating
a security vulnerability in your app that can be exploited. Instead,
consider using one of these documented methods which are not
deprecated: http://api.rubyonrails.org/v#{ActionPack.version}/classes/ActionController/Parameters.html
".squish
ActiveSupport::Deprecation.warn(message)
@parameters.public_send(method_sym, *args, &block)
else
super
end
end # File actionpack/lib/action_controller/metal/strong_parameters.rb, line 538
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 Возвращает новый ActionController::Parameters экземпляр, содержащий только указанные filters и устанавливает атрибут permitted для объекта в значение true. Это полезно для ограничения атрибутов, которые должны быть разрешены для массового обновления.
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
Только разрешенные скалярные значения проходят фильтр. Например, при
params.permit(:name)
:name проходит, если это ключ params, связанный со значением типа String, Symbol, NilClass, Numeric, TrueClass, FalseClass, Date, Time, DateTime, StringIO, IO, ActionDispatch::Http::UploadedFile или Rack::Test::UploadedFile. В противном случае ключ :name отфильтровывается.
Вы можете указать, что параметр должен быть массивом разрешенных скаляров, сопоставив его с пустым массивом:
params = ActionController::Parameters.new(tags: ["rails", "parameters"]) params.permit(tags: [])
Вы также можете использовать permit для вложенных параметров, например:
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
Обратите внимание, что если вы используете permit в ключе, указывающем на хэш, это не разрешит весь хэш. Вам также необходимо указать, какие атрибуты внутри хэша должны быть включены в список разрешенных.
params = ActionController::Parameters.new({
person: {
contact: {
email: "none@test.com",
phone: "555-1234"
}
}
})
params.require(:person).permit(:contact)
# => <ActionController::Parameters {} permitted: true>
params.require(:person).permit(contact: :phone)
# => <ActionController::Parameters {"contact"=><ActionController::Parameters {"phone"=>"555-1234"} permitted: true>} permitted: true>
params.require(:person).permit(contact: [ :email, :phone ])
# => <ActionController::Parameters {"contact"=><ActionController::Parameters {"email"=>"none@test.com", "phone"=>"555-1234"} permitted: true>} permitted: true>
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 395
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 в значение true. Это можно использовать для массового назначения. Возвращает 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 actionpack/lib/action_controller/metal/strong_parameters.rb, line 379 def permitted? @permitted end
Возвращает true если параметр разрешен, false в противном случае.
params = ActionController::Parameters.new params.permitted? # => false params.permit! params.permitted? # => true
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 711 def reject(&block) new_instance_with_inherited_permitted_status(@parameters.reject(&block)) end
Возвращает новый экземпляр ActionController::Parameters с удаленными элементами, для которых блок возвращает true.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 716 def reject!(&block) @parameters.reject!(&block) self end
Удаляет элементы, для которых блок возвращает true, и возвращает self.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 456
def require(key)
return key.map { |k| require(k) } if key.is_a?(Array)
value = self[key]
if value.present? || value == false
value
else
raise ParameterMissing.new(key)
end
end Этот метод принимает как одиночный ключ, так и массив ключей.
При передаче одного ключа, если он существует и его связанное значение присутствует или равно одиночному объекту false, возвращает это значение:
ActionController::Parameters.new(person: { name: "Francesco" }).require(:person)
# => <ActionController::Parameters {"name"=>"Francesco"} permitted: false>
В противном случае генерирует исключение ActionController::ParameterMissing:
ActionController::Parameters.new.require(:person)
# ActionController::ParameterMissing: param is missing or the value is empty: person
ActionController::Parameters.new(person: nil).require(:person)
# ActionController::ParameterMissing: param is missing or the value is empty: person
ActionController::Parameters.new(person: "\t").require(:person)
# ActionController::ParameterMissing: param is missing or the value is empty: person
ActionController::Parameters.new(person: {}).require(:person)
# ActionController::ParameterMissing: param is missing or the value is empty: person
При передаче массива ключей метод пытается потребовать каждый из них в порядке. Если это удается, возвращается массив соответствующих возвращаемых значений:
params = ActionController::Parameters.new(user: { ... }, profile: { ... })
user_params, profile_params = params.require([:user, :profile]) В противном случае метод повторно генерирует первое возникшее исключение:
params = ActionController::Parameters.new(user: {}, profile: {})
user_params, profile_params = params.require([:user, :profile])
# ActionController::ParameterMissing: param is missing or the value is empty: user
Технически этот метод может использоваться для извлечения конечных значений:
# CAREFUL
params = ActionController::Parameters.new(person: { name: "Finn" })
name = params.require(:person).require(:name) # CAREFUL
но имейте в виду, что в какой-то момент эти значения нужно будет разрешить:
def person_params
params.require(:person).permit(:name).tap do |person_params|
person_params.require(:name) # SAFER
end
end
например.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 698 def select(&block) new_instance_with_inherited_permitted_status(@parameters.select(&block)) end
Возвращает новый экземпляр ActionController::Parameters только с элементами, для которых блок возвращает true.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 703 def select!(&block) @parameters.select!(&block) self end
Эквивалент Hash#keep_if, но возвращает nil, если изменений не было.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 616 def slice(*keys) new_instance_with_inherited_permitted_status(@parameters.slice(*keys)) end
Возвращает новый экземпляр ActionController::Parameters содержащий только указанные keys. Если указанные keys не существуют, возвращается пустой хэш.
params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
params.slice(:a, :b) # => <ActionController::Parameters {"a"=>1, "b"=>2} permitted: false>
params.slice(:d) # => <ActionController::Parameters {} permitted: false>
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 622 def slice!(*keys) @parameters.slice!(*keys) self end
Возвращает текущий экземпляр ActionController::Parameters содержащий только указанные keys.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 269
def to_h
if permitted?
convert_parameters_to_hashes(@parameters, :to_h)
elsif self.class.raise_on_unfiltered_parameters
raise UnfilteredParameters
else
slice(*self.class.always_permitted_parameters).permit!.to_h
end
end Возвращает безопасное представление ActiveSupport::HashWithIndifferentAccess параметров с удаленными всеми неразрешенными ключами.
params = ActionController::Parameters.new({
name: "Senjougahara Hitagi",
oddity: "Heavy stone crab"
})
params.to_h
# => ActionController::UnfilteredParameters: unable to convert unfiltered parameters to hash
safe_params = params.permit(:name)
safe_params.to_h # => {"name"=>"Senjougahara Hitagi"}
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 291
def to_hash
if self.class.raise_on_unfiltered_parameters || permitted?
to_h.to_hash
else
message = " #to_hash unexpectedly ignores parameter filtering, and will change to enforce it in Rails 5.1.
Enable `raise_on_unfiltered_parameters` to respect parameter filtering, which is the default
in new applications. For the existing deprecated behaviour, call #to_unsafe_h instead.
".squish
ActiveSupport::Deprecation.warn(message)
@parameters.to_hash
end
end Возвращает безопасное представление Hash параметров с удаленными всеми неразрешенными ключами.
params = ActionController::Parameters.new({
name: "Senjougahara Hitagi",
oddity: "Heavy stone crab"
})
params.to_hash
# => ActionController::UnfilteredParameters: unable to convert unfiltered parameters to hash
safe_params = params.permit(:name)
safe_params.to_hash # => {"name"=>"Senjougahara Hitagi"}
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 329
def to_query(*args)
if self.class.raise_on_unfiltered_parameters
to_h.to_query(*args)
else
@parameters.to_query(*args)
end
end Возвращает строковое представление получателя, подходящее для использования в строке запроса URL:
params = ActionController::Parameters.new({
name: "David",
nationality: "Danish"
})
params.to_query
# => "name=David&nationality=Danish"
Можно передать необязательный префикс для обертки имен ключей:
params = ActionController::Parameters.new({
name: "David",
nationality: "Danish"
})
params.to_query("user")
# => "user%5Bname%5D=David&user%5Bnationality%5D=Danish"
Строки пар «ключ=значение», составляющие строку запроса, сортируются лексикографически в порядке возрастания.
Этот метод также алиасируется как to_param.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 189
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 348 def to_unsafe_h convert_parameters_to_hashes(@parameters, :to_unsafe_h) end
Возвращает небезопасное, неотфильтрованное представление ActiveSupport::HashWithIndifferentAccess параметров.
params = ActionController::Parameters.new({
name: "Senjougahara Hitagi",
oddity: "Heavy stone crab"
})
params.to_unsafe_h
# => {"name"=>"Senjougahara Hitagi", "oddity" => "Heavy stone crab"}
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 671
def transform_keys(&block)
if block
new_instance_with_inherited_permitted_status(
@parameters.transform_keys(&block)
)
else
@parameters.transform_keys
end
end Возвращает новый экземпляр ActionController::Parameters с результатами выполнения block для каждого ключа. Значения остаются неизменными.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 683 def transform_keys!(&block) @parameters.transform_keys!(&block) self end
Выполняет преобразование ключей и возвращает изменённый ActionController::Parameters экземпляр.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 652
def transform_values(&block)
if block
new_instance_with_inherited_permitted_status(
@parameters.transform_values(&block)
)
else
@parameters.transform_values
end
end Возвращает новый ActionController::Parameters с результатами выполнения block один раз для каждого значения. Ключи остаются неизменными.
params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
params.transform_values { |x| x * 2 }
# => <ActionController::Parameters {"a"=>2, "b"=>4, "c"=>6} permitted: false>
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 664 def transform_values!(&block) @parameters.transform_values!(&block) self end
Выполняет преобразование значений и возвращает изменённый ActionController::Parameters экземпляр.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 197
Возвращает true, если заданное значение присутствует для какого-то ключа в параметрах.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 204 delegate :keys, :key?, :has_key?, :values, :has_value?, :value?, :empty?, :include?, :as_json, :to_s, to: :@parameters
Возвращает новый массив значений параметров.
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 724 def values_at(*keys) convert_value_to_parameters(@parameters.values_at(*keys)) end
Возвращает значения, которые были назначены заданным keys. Обратите внимание, что все Hash объекты будут преобразованы в ActionController::Parameters.
Защищённые методы экземпляра
# File actionpack/lib/action_controller/metal/strong_parameters.rb, line 817
def fields_for_style?
@parameters.all? { |k, v| k =~ /\A-?\d+\z/ && (v.is_a?(Hash) || v.is_a?(Parameters)) }
end # File actionpack/lib/action_controller/metal/strong_parameters.rb, line 813 def permitted=(new_permitted) @permitted = new_permitted end
© 2004–2018 David Heinemeier Hansson
Licensed under the MIT License.