Skip to content
This repository has been archived by the owner on Aug 17, 2017. It is now read-only.

Commit

Permalink
Merge pull request #117 from d-Pixie/master
Browse files Browse the repository at this point in the history
Allow multiple keys in call to require
  • Loading branch information
dhh committed Apr 17, 2013
2 parents c789f57 + 7758a34 commit 59f3365
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 9 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,16 @@ This declaration whitelists the `name`, `emails` and `friends` attributes. It is

Thanks to Nick Kallen for the permit idea!

## Requiring multiple values

In some cases you might want to require several parameters to be present before proceeding, such as for an API where the params might be a flat hash. You can use `require` to do this:

``` ruby
params.require(:username, :password).permit(:version)
```

When used with multiple inputs `require` raises a `ActionController::MissingParameter` error with *all* the missing attributes specified in the message. If no values are missing the params hash is returned unmodified.

## Handling of Unpermitted Keys

By default parameter keys that are not explicitly permitted will be logged in the development and test environment. In other environments these parameters will simply be filtered out and ignored.
Expand Down
29 changes: 23 additions & 6 deletions lib/action_controller/parameters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class UnpermittedParameters < IndexError

def initialize(params)
@params = params
super("found unpermitted parameters: #{params.join(", ")}")
super("found unpermitted parameter(s): #{params.join(", ")}")
end
end

Expand Down Expand Up @@ -51,8 +51,12 @@ def permit!
self
end

def require(key)
self[key].presence || raise(ActionController::ParameterMissing.new(key))
def require(*keys)
if keys.many?
require_multiple(keys)
else
require_single(keys)
end
end

alias :required :require
Expand Down Expand Up @@ -98,6 +102,20 @@ def dup
end

protected
def require_single(keys)
key = keys.first
self[key].presence || raise(ActionController::ParameterMissing.new(key))
end

def require_multiple(keys)
missing_keys = keys.select do |key|
self[key].blank?
end

raise(ActionController::ParameterMissing.new(missing_keys.join(', '))) if missing_keys.compact.any?
self
end

def convert_value(value)
if value.class == Hash
self.class.new_from_hash_copying_default(value)
Expand All @@ -109,7 +127,6 @@ def convert_value(value)
end

private

def convert_hashes_to_parameters(key, value)
if value.is_a?(Parameters) || !value.is_a?(Hash)
value
Expand Down Expand Up @@ -217,7 +234,7 @@ def unpermitted_parameters!(params)
unpermitted_keys = unpermitted_keys(params)

if unpermitted_keys.any?
case self.class.action_on_unpermitted_parameters
case self.class.action_on_unpermitted_parameters
when :log
name = "unpermitted_parameters.action_controller"
ActiveSupport::Notifications.instrument(name, :keys => unpermitted_keys)
Expand All @@ -237,7 +254,7 @@ module StrongParameters

included do
rescue_from(ActionController::ParameterMissing) do |parameter_missing_exception|
render :text => "Required parameter missing: #{parameter_missing_exception.param}", :status => :bad_request
render :text => "Required parameter(s) missing: #{parameter_missing_exception.param}", :status => :bad_request
end
end

Expand Down
2 changes: 1 addition & 1 deletion test/action_controller_required_params_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ class ActionControllerRequiredParamsTest < ActionController::TestCase

test "missing parameters will be mentioned in the return" do
post :create, { :magazine => { :name => "Mjallo!" } }
assert_equal "Required parameter missing: book", response.body
assert_match "book", response.body
end
end
4 changes: 2 additions & 2 deletions test/log_on_unpermitted_params_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def teardown
:fishing => "Turnips"
})

assert_logged("Unpermitted parameters: fishing") do
assert_logged("Unpermitted parameter(s): fishing") do
params.permit(:book => [:pages])
end
end
Expand All @@ -26,7 +26,7 @@ def teardown
:book => { :pages => 65, :title => "Green Cats and where to find then." }
})

assert_logged("Unpermitted parameters: title") do
assert_logged("Unpermitted parameter(s): title") do
params.permit(:book => [:pages])
end
end
Expand Down
25 changes: 25 additions & 0 deletions test/parameters_require_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,29 @@ class ParametersRequireTest < ActiveSupport::TestCase
ActionController::Parameters.new(:person => {}).require(:person)
end
end

test "permit multiple required parameters" do
params = ActionController::Parameters.new(:username => 'user', :password => '<3<3<3<3')
assert_nothing_raised(ActionController::ParameterMissing) do
params.require(:username, :password)
end

assert params.has_key?(:username)
assert params.has_key?(:password)
end

test "multiple required parameters must be present not merely not nil" do
params = ActionController::Parameters.new(:username => '', :password => nil)
assert_raises(ActionController::ParameterMissing) do
params.require(:username, :password)
end
end

test "all parameters are returned after required with multiple parameters" do
params = ActionController::Parameters.new(:username => 'user', :password => '<3<3<3<3', :version => 1)

params.require(:username, :password)

assert params.has_key?(:version)
end
end

0 comments on commit 59f3365

Please sign in to comment.