diff options
author | David Heinemeier Hansson <david@loudthinking.com> | 2012-09-18 12:33:13 -0700 |
---|---|---|
committer | David Heinemeier Hansson <david@loudthinking.com> | 2012-09-18 12:33:13 -0700 |
commit | c49d959e9d40101f1712a452004695f4ce27d84c (patch) | |
tree | f87077668c14ed414e3d819212b0813e74551c8f /actionpack/lib/action_controller/metal/strong_parameters.rb | |
parent | ade701045f0f80399d99151e5583d4f86c68678e (diff) | |
parent | 3919fcd61ef999aab9397332ce3017870b184766 (diff) | |
download | rails-c49d959e9d40101f1712a452004695f4ce27d84c.tar.gz rails-c49d959e9d40101f1712a452004695f4ce27d84c.tar.bz2 rails-c49d959e9d40101f1712a452004695f4ce27d84c.zip |
Merge pull request #7251 from rails/integrate-strong_parameters
Integrate strong_parameters in Rails 4
Diffstat (limited to 'actionpack/lib/action_controller/metal/strong_parameters.rb')
-rw-r--r-- | actionpack/lib/action_controller/metal/strong_parameters.rb | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb new file mode 100644 index 0000000000..c3c1921706 --- /dev/null +++ b/actionpack/lib/action_controller/metal/strong_parameters.rb @@ -0,0 +1,125 @@ +require 'active_support/concern' +require 'active_support/core_ext/hash/indifferent_access' +require 'active_support/rescuable' + +module ActionController + class ParameterMissing < KeyError + attr_reader :param + + def initialize(param) + @param = param + super("key not found: #{param}") + end + end + + class Parameters < ActiveSupport::HashWithIndifferentAccess + cattr_accessor :permit_all_parameters, instance_accessor: false + attr_accessor :permitted + alias :permitted? :permitted + + def initialize(attributes = nil) + super(attributes) + @permitted = self.class.permit_all_parameters + end + + def permit! + @permitted = true + self + end + + def require(key) + self[key].presence || raise(ParameterMissing.new(key)) + end + + alias :required :require + + def permit(*filters) + params = self.class.new + + filters.each do |filter| + case filter + when Symbol, String then + params[filter] = self[filter] if has_key?(filter) + when Hash then + self.slice(*filter.keys).each do |key, value| + return unless value + + key = key.to_sym + + params[key] = each_element(value) 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 + end + end + + params.permit! + end + + def [](key) + convert_hashes_to_parameters(key, super) + end + + def fetch(key, *args) + convert_hashes_to_parameters(key, super) + rescue KeyError + raise ActionController::ParameterMissing.new(key) + end + + def slice(*keys) + self.class.new(super) + end + + def dup + super.tap do |duplicate| + duplicate.instance_variable_set :@permitted, @permitted + end + end + + private + def convert_hashes_to_parameters(key, value) + if value.is_a?(Parameters) || !value.is_a?(Hash) + value + else + # Convert to Parameters on first access + self[key] = self.class.new(value) + end + end + + def each_element(object) + if object.is_a?(Array) + object.map { |el| yield el }.compact + elsif object.is_a?(Hash) && object.keys.all? { |k| k =~ /\A-?\d+\z/ } + hash = object.class.new + object.each { |k,v| hash[k] = yield v } + hash + else + yield object + end + end + end + + module StrongParameters + extend ActiveSupport::Concern + include ActiveSupport::Rescuable + + included do + rescue_from(ActionController::ParameterMissing) do |parameter_missing_exception| + render text: "Required parameter missing: #{parameter_missing_exception.param}", status: :bad_request + end + end + + def params + @_params ||= Parameters.new(request.parameters) + end + + def params=(val) + @_params = val.is_a?(Hash) ? Parameters.new(val) : val + end + end +end |