123456789_123456789_123456789_123456789_123456789_

Class: ActionDispatch::ParamBuilder

Relationships & Source Files
Inherits: Object
Defined in: actionpack/lib/action_dispatch/http/param_builder.rb

Constant Summary

Class Attribute Summary

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.new(param_depth_limit) ⇒ ParamBuilder

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/param_builder.rb', line 15

def initialize(param_depth_limit)
  @param_depth_limit = param_depth_limit
end

Class Attribute Details

.default (rw) Also known as: #default

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/param_builder.rb', line 23

cattr_accessor :default

.ignore_leading_brackets (rw) Also known as: #ignore_leading_brackets

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/param_builder.rb', line 19

cattr_accessor :ignore_leading_brackets

Class Method Details

.make_default(param_depth_limit)

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/param_builder.rb', line 9

def self.make_default(param_depth_limit)
  new param_depth_limit
end

Instance Attribute Details

#default (rw)

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/param_builder.rb', line 23

cattr_accessor :default

#from_hash(hash, encoding_template: nil) (readonly)

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/param_builder.rb', line 50

delegate :from_query_string, :from_pairs, :from_hash, to: :default

#from_pairs(pairs, encoding_template: nil) (readonly)

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/param_builder.rb', line 34

delegate :from_query_string, :from_pairs, :from_hash, to: :default

#from_query_string(qs, separator: nil, encoding_template: nil) (readonly)

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/param_builder.rb', line 30

delegate :from_query_string, :from_pairs, :from_hash, to: :default

#ignore_leading_brackets (rw)

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/param_builder.rb', line 19

cattr_accessor :ignore_leading_brackets

#param_depth_limit (readonly)

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/param_builder.rb', line 13

attr_reader :param_depth_limit

Instance Method Details

#make_params (private)

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/param_builder.rb', line 162

def make_params
  ActiveSupport::HashWithIndifferentAccess.new
end

#new_depth_limit(param_depth_limit) (private)

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/param_builder.rb', line 166

def new_depth_limit(param_depth_limit)
  self.class.new @params_class, param_depth_limit
end

#params_hash_has_key?(hash, key) ⇒ Boolean (private)

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/param_builder.rb', line 174

def params_hash_has_key?(hash, key)
  return false if key.include?("[]")

  key.split(/[\[\]]+/).inject(hash) do |h, part|
    next h if part == ""
    return false unless params_hash_type?(h) && h.key?(part)
    h[part]
  end

  true
end

#params_hash_type?(obj) ⇒ Boolean (private)

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/param_builder.rb', line 170

def params_hash_type?(obj)
  Hash === obj
end

#store_nested_param(params, name, v, depth, encoding_template = nil) (private)

Raises:

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/param_builder.rb', line 65

def store_nested_param(params, name, v, depth, encoding_template = nil)
  raise ParamsTooDeepError if depth >= param_depth_limit

  if !name
    # nil name, treat same as empty string (required by tests)
    k = after = ""
  elsif depth == 0
    if ignore_leading_brackets || (ignore_leading_brackets.nil? && LEADING_BRACKETS_COMPAT)
      # Rack 2 compatible behavior, ignore leading brackets
      if name =~ /\A[\[\]]*([^\[\]]+)\]*/
        k = $1
        after = $' || ""

        if !ignore_leading_brackets && (k != $& || !after.empty? && !after.start_with?("["))
          ActionDispatch.deprecator.warn("Skipping over leading brackets in parameter name #{name.inspect} is deprecated and will parse differently in Rails 8.1 or Rack 3.0.")
        end
      else
        k = name
        after = ""
      end
    else
      # Start of parsing, don't treat [] or [ at start of string specially
      if start = name.index("[", 1)
        # Start of parameter nesting, use part before brackets as key
        k = name[0, start]
        after = name[start, name.length]
      else
        # Plain parameter with no nesting
        k = name
        after = ""
      end
    end
  elsif name.start_with?("[]")
    # Array nesting
    k = "[]"
    after = name[2, name.length]
  elsif name.start_with?("[") && (start = name.index("]", 1))
    # Hash nesting, use the part inside brackets as the key
    k = name[1, start - 1]
    after = name[start + 1, name.length]
  else
    # Probably malformed input, nested but not starting with [
    # treat full name as key for backwards compatibility.
    k = name
    after = ""
  end

  return if k.empty?

  if depth == 0 && String === v
    # We have to wait until we've found the top part of the name,
    # because that's what the encoding template is configured with
    if encoding_template && (designated_encoding = encoding_template[k]) && !v.frozen?
      v.force_encoding(designated_encoding)
    end

    # ... and we can't validate the encoding until after we've
    # applied any template override
    unless v.valid_encoding?
      raise InvalidParameterError, "Invalid encoding for parameter: #{v.scrub}"
    end
  end

  if after == ""
    if k == "[]" && depth != 0
      return (v || !ActionDispatch::Request::Utils.perform_deep_munge) ? [v] : []
    else
      params[k] = v
    end
  elsif after == "["
    params[name] = v
  elsif after == "[]"
    params[k] ||= []
    raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
    params[k] << v if v || !ActionDispatch::Request::Utils.perform_deep_munge
  elsif after.start_with?("[]")
    # Recognize x[][y] (hash inside array) parameters
    unless after[2] == "[" && after.end_with?("]") && (child_key = after[3, after.length - 4]) && !child_key.empty? && !child_key.index("[") && !child_key.index("]")
      # Handle other nested array parameters
      child_key = after[2, after.length]
    end
    params[k] ||= []
    raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
    if params_hash_type?(params[k].last) && !params_hash_has_key?(params[k].last, child_key)
      store_nested_param(params[k].last, child_key, v, depth + 1)
    else
      params[k] << store_nested_param(make_params, child_key, v, depth + 1)
    end
  else
    params[k] ||= make_params
    raise ParameterTypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params_hash_type?(params[k])
    params[k] = store_nested_param(params[k], after, v, depth + 1)
  end

  params
end