diff options
author | Xavier Noria <fxn@hashref.com> | 2013-01-20 17:59:53 +0100 |
---|---|---|
committer | Xavier Noria <fxn@hashref.com> | 2013-01-20 17:59:53 +0100 |
commit | cbec22ce5783c9530b3e2735a8e13eeeca00e0d2 (patch) | |
tree | ecad6bfedddfbd7a82060c2f10cdf3d3252a715c /actionpack/lib | |
parent | 996aba341ace42393f4e2cd7c00489dac20f2bd3 (diff) | |
download | rails-cbec22ce5783c9530b3e2735a8e13eeeca00e0d2.tar.gz rails-cbec22ce5783c9530b3e2735a8e13eeeca00e0d2.tar.bz2 rails-cbec22ce5783c9530b3e2735a8e13eeeca00e0d2.zip |
strong parameters filters permitted scalars
Diffstat (limited to 'actionpack/lib')
-rw-r--r-- | actionpack/lib/action_controller/metal/strong_parameters.rb | 114 |
1 files changed, 92 insertions, 22 deletions
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb index 2c96e03f55..02d9c0b4fb 100644 --- a/actionpack/lib/action_controller/metal/strong_parameters.rb +++ b/actionpack/lib/action_controller/metal/strong_parameters.rb @@ -184,6 +184,20 @@ module ActionController # 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+, or +IO+. 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.permit(:tags => []) + # # You can also use +permit+ on nested parameters, like: # # params = ActionController::Parameters.new({ @@ -230,29 +244,10 @@ module ActionController filters.flatten.each do |filter| case filter - when Symbol, String then - if has_key?(filter) - _value = self[filter] - params[filter] = _value unless Hash === _value - end - keys.grep(/\A#{Regexp.escape(filter)}\(\d+[if]?\)\z/) { |key| params[key] = self[key] } + when Symbol, String + permitted_scalar_filter(params, filter) when Hash then - filter = filter.with_indifferent_access - - self.slice(*filter.keys).each do |key, values| - return unless values - - key = key.to_sym - - params[key] = each_element(values) do |value| - # filters are a Hash, so we expect value to be a Hash too - next if filter.is_a?(Hash) && !value.is_a?(Hash) - - value = self.class.new(value) if !value.respond_to?(:permit) - - value.permit(*Array.wrap(filter[key])) - end - end + hash_filter(params, filter) end end @@ -352,6 +347,81 @@ module ActionController def unpermitted_keys(params) self.keys - params.keys - NEVER_UNPERMITTED_PARAMS end + + # + # --- Filtering ---------------------------------------------------------- + # + + # 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. + PERMITTED_SCALAR_TYPES = [ + String, + Symbol, + NilClass, + Numeric, + TrueClass, + FalseClass, + Date, + Time, + # DateTimes are Dates, we document the type but avoid the redundant check. + StringIO, + IO, + ] + + def permitted_scalar?(value) + PERMITTED_SCALAR_TYPES.any? {|type| value.is_a?(type)} + end + + 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/).each do |key| + if permitted_scalar?(self[key]) + params[key] = self[key] + end + end + end + + def array_of_permitted_scalars?(value) + if value.is_a?(Array) + value.all? {|element| permitted_scalar?(element)} + end + end + + def array_of_permitted_scalars_filter(params, key) + if has_key?(key) && array_of_permitted_scalars?(self[key]) + params[key] = self[key] + end + end + + def hash_filter(params, filter) + filter = filter.with_indifferent_access + + # Slicing filters out non-declared keys. + slice(*filter.keys).each do |key, value| + return unless value + + if filter[key] == [] + # Declaration {:comment_ids => []}. + array_of_permitted_scalars_filter(params, key) + else + # Declaration {:user => :name} or {:user => [:name, :age, {:adress => ...}]}. + 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 end # == Strong \Parameters |