class ActiveSupport::ParameterFilter
end])
v.reverse! if /secret/i.match?(k)
ActiveSupport::ParameterFilter.new([-> (k, v) do
# Reverses values for keys that match /secret/i.<br><br>ActiveSupport::ParameterFilter.new()
# Does not change ‘{ file: { code: “xxxx” } }`.
# Replaces the value for :code in `{ credit_card: { code: “xxxx” } }`.
ActiveSupport::ParameterFilter.new([/Apinz/, /Apin_/])
# substring, such as “shipping_id”.
# “pin_”. Does not match keys that otherwise include “pin” as a
# Replaces values for the exact key “pin” and for keys that begin with
ActiveSupport::ParameterFilter.new([:foo, “bar”])
# Replaces values with “[FILTERED]” for keys that match /foo|bar/i.<br><br>ActiveSupport::ParameterFilter.new()
# Replaces values with “[FILTERED]” for keys that match /password/i.
then be mutated as desired using methods such as String#replace
.
and of any nested Hash
es will be passed to it. The value or key can
If a proc is given as a filter, each key and value of the Hash
-like"credit_card.number"
.
Matching based on nested keys is possible by using dot notation, e.g.
keys match one of the specified filters.ParameterFilter
replaces values in a Hash
-like object if their
= Active Support Parameter Filter
def self.precompile_filters(filters)
ActiveSupport::ParameterFilter.new(precompiled)
# => [/(?-mix:foo)|(?i:bar)/, /(?i:nested\.baz)|(?-mix:nested\.qux)/]
precompiled = ActiveSupport::ParameterFilter.precompile_filters(filters)
filters = [/foo/, :bar, "nested.baz", /nested\.qux/]
precompiled filters can be retained).
where the ParameterFilter instance itself cannot be retained (but the
precompilation can improve filtering performance, especially in the case
#initialize. Depending on the quantity and types of filters,
Precompiles an array of filters that otherwise would be passed directly to
def self.precompile_filters(filters) filters, patterns = filters.partition { |filter| filter.is_a?(Proc) } patterns.map! do |pattern| pattern.is_a?(Regexp) ? pattern : "(?i:#{Regexp.escape pattern.to_s})" end deep_patterns = patterns.extract! { |pattern| pattern.to_s.include?("\\.") } filters << Regexp.new(patterns.join("|")) if patterns.any? filters << Regexp.new(deep_patterns.join("|")) if deep_patterns.any? filters end
def call(params, full_parent_key = nil, original_params = params)
def call(params, full_parent_key = nil, original_params = params) filtered_params = params.class.new params.each do |key, value| filtered_params[key] = value_for_key(key, value, full_parent_key, original_params) end filtered_params end
def compile_filters!(filters)
def compile_filters!(filters) @no_filters = filters.empty? return if @no_filters @regexps, strings = [], [] @deep_regexps, deep_strings = nil, nil @blocks = nil filters.each do |item| case item when Proc (@blocks ||= []) << item when Regexp if item.to_s.include?("\\.") (@deep_regexps ||= []) << item else @regexps << item end else s = Regexp.escape(item.to_s) if s.include?("\\.") (deep_strings ||= []) << s else strings << s end end end @regexps << Regexp.new(strings.join("|"), true) unless strings.empty? (@deep_regexps ||= []) << Regexp.new(deep_strings.join("|"), true) if deep_strings end
def filter(params)
def filter(params) @no_filters ? params.dup : call(params) end
def filter_param(key, value)
def filter_param(key, value) @no_filters ? value : value_for_key(key, value) end
def initialize(filters = [], mask: FILTERED)
==== Options
For +Proc+ filters, key, value, and optional original hash is passed to block arguments.
Other types of filters are treated as +String+ using +to_s+.
Create instance with given filters. Supported type of filters are +String+, +Regexp+, and +Proc+.
def initialize(filters = [], mask: FILTERED) @mask = mask compile_filters!(filters) end
def value_for_key(key, value, full_parent_key = nil, original_params = nil)
def value_for_key(key, value, full_parent_key = nil, original_params = nil) if @deep_regexps full_key = full_parent_key ? "#{full_parent_key}.#{key}" : key.to_s end if @regexps.any? { |r| r.match?(key.to_s) } value = @mask elsif @deep_regexps&.any? { |r| r.match?(full_key) } value = @mask elsif value.is_a?(Hash) value = call(value, full_key, original_params) elsif value.is_a?(Array) value = value.map { |v| value_for_key(key, v, full_parent_key, original_params) } elsif @blocks key = key.dup if key.duplicable? value = value.dup if value.duplicable? @blocks.each { |b| b.arity == 2 ? b.call(key, value) : b.call(key, value, original_params) } end value end