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 | |
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')
-rw-r--r-- | actionpack/lib/action_controller.rb | 2 | ||||
-rw-r--r-- | actionpack/lib/action_controller/base.rb | 1 | ||||
-rw-r--r-- | actionpack/lib/action_controller/metal/params_wrapper.rb | 9 | ||||
-rw-r--r-- | actionpack/lib/action_controller/metal/strong_parameters.rb | 125 | ||||
-rw-r--r-- | actionpack/lib/action_controller/railtie.rb | 4 |
5 files changed, 134 insertions, 7 deletions
diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index 8c1f548e47..1a13d7af29 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -2,6 +2,7 @@ require 'active_support/rails' require 'abstract_controller' require 'action_dispatch' require 'action_controller/metal/live' +require 'action_controller/metal/strong_parameters' module ActionController extend ActiveSupport::Autoload @@ -34,6 +35,7 @@ module ActionController autoload :Rescue autoload :Responder autoload :Streaming + autoload :StrongParameters autoload :Testing autoload :UrlFor end diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 84e8c2a698..6b8d9384d4 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -214,6 +214,7 @@ module ActionController Caching, MimeResponds, ImplicitRender, + StrongParameters, Cookies, Flash, diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb index 2736948ce0..bbb711b49d 100644 --- a/actionpack/lib/action_controller/metal/params_wrapper.rb +++ b/actionpack/lib/action_controller/metal/params_wrapper.rb @@ -42,9 +42,7 @@ module ActionController # end # # On ActiveRecord models with no +:include+ or +:exclude+ option set, - # if attr_accessible is set on that model, it will only wrap the accessible - # parameters, else it will only wrap the parameters returned by the class - # method attribute_names. + # it will only wrap the parameters returned by the class method attribute_names. # # If you're going to pass the parameters to an +ActiveModel+ object (such as # <tt>User.new(params[:user])</tt>), you might consider passing the model class to @@ -165,10 +163,7 @@ module ActionController unless options[:include] || options[:exclude] model ||= _default_wrap_model - role = options.fetch(:as, :default) - if model.respond_to?(:accessible_attributes) && model.accessible_attributes(role).present? - options[:include] = model.accessible_attributes(role).to_a - elsif model.respond_to?(:attribute_names) && model.attribute_names.present? + if model.respond_to?(:attribute_names) && model.attribute_names.present? options[:include] = model.attribute_names end end 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 diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index 3ecc105e22..d7e8194bf6 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -19,6 +19,10 @@ module ActionController ActionController::Helpers.helpers_path = app.helpers_paths end + initializer "action_controller.parameters_config" do |app| + ActionController::Parameters.permit_all_parameters = app.config.action_controller.delete(:permit_all_parameters) + end + initializer "action_controller.set_configs" do |app| paths = app.config.paths options = app.config.action_controller |