aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_controller
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_controller')
-rw-r--r--actionpack/lib/action_controller/base.rb1
-rw-r--r--actionpack/lib/action_controller/metal/params_wrapper.rb9
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb125
-rw-r--r--actionpack/lib/action_controller/railtie.rb4
4 files changed, 132 insertions, 7 deletions
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