Skip to content

Commit

Permalink
Merged #433.
Browse files Browse the repository at this point in the history
  • Loading branch information
dblock committed Aug 19, 2013
2 parents 609648c + b7b51e6 commit ff20cd4
Show file tree
Hide file tree
Showing 9 changed files with 54 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Next Release
* [#450](https://github.com/intridea/grape/pull/450): Added option to pass an exception handler lambda as an argument to `rescue_from` - [@robertopedroso](https://github.com/robertopedroso).
* [#443](https://github.com/intridea/grape/pull/443): Let `requires` and `optional` take blocks that initialize new scopes - [@asross](https://github.com/asross).
* [#452](https://github.com/intridea/grape/pull/452): Added `with` as a hash option to specify handlers for `rescue_from` and `error_formatter` [@robertopedroso](https://github.com/robertopedroso).
* [#433](https://github.com/intridea/grape/issues/433): API change: validation errors are now collected and a `Grape::Exceptions::Validations` is raised; the individual validation errors can be accessed via `Grape::Exceptions::Validations#errors` - [@stevschmid](https://github.com/stevschmid).
* Your contribution here.

#### Fixes
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -420,16 +420,16 @@ end

### Validation Errors

When validation and coercion errors occur an exception of type `Grape::Exceptions::Validation` is raised.
Validation and coercion errors are collected and an exception of type `Grape::Exceptions::Validations` is raised.
If the exception goes uncaught it will respond with a status of 400 and an error message.
You can rescue a `Grape::Exceptions::Validation` and respond with a custom response.
You can rescue a `Grape::Exceptions::Validations` and respond with a custom response.

```ruby
rescue_from Grape::Exceptions::Validation do |e|
rescue_from Grape::Exceptions::Validations do |e|
Rack::Response.new({
'status' => e.status,
'message' => e.message,
'param' => e.param
'errors' => e.errors
}.to_json, e.status)
end
```
Expand Down
1 change: 1 addition & 0 deletions lib/grape.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ module Grape
module Exceptions
autoload :Base, 'grape/exceptions/base'
autoload :Validation, 'grape/exceptions/validation'
autoload :Validations, 'grape/exceptions/validations'
autoload :MissingVendorOption, 'grape/exceptions/missing_vendor_option'
autoload :MissingMimeType, 'grape/exceptions/missing_mime_type'
autoload :MissingOption, 'grape/exceptions/missing_option'
Expand Down
11 changes: 10 additions & 1 deletion lib/grape/endpoint.rb
Original file line number Diff line number Diff line change
Expand Up @@ -391,8 +391,17 @@ def run(env)
run_filters befores

# Retieve validations from this namespace and all parent namespaces.
validation_errors = []
settings.gather(:validations).each do |validator|
validator.validate!(params)
begin
validator.validate!(params)
rescue Grape::Exceptions::Validation => e
validation_errors << e
end
end

if validation_errors.any?
raise Grape::Exceptions::Validations, errors: validation_errors
end

run_filters after_validations
Expand Down
2 changes: 1 addition & 1 deletion lib/grape/exceptions/validation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class Validation < Grape::Exceptions::Base
def initialize(args = {})
@param = args[:param].to_s if args.has_key? :param
attribute = translate_attribute(@param)
args[:message] = translate_message(args[:message_key], :attribute => attribute)
args[:message] = translate_message(args[:message_key], :attribute => attribute) if args.has_key? :message_key
super
end
end
Expand Down
15 changes: 15 additions & 0 deletions lib/grape/exceptions/validations.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
require 'grape/exceptions/base'

module Grape
module Exceptions
class Validations < Grape::Exceptions::Base
attr_accessor :errors

def initialize(args = {})
@errors = args[:errors]
errors_as_sentence = @errors.collect { |e| e.message }.join(', ')
super message: errors_as_sentence, status: 400
end
end
end
end
1 change: 1 addition & 0 deletions lib/grape/validations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ def validates(attrs, validations)
# Validate for presence before any other validators
if validations.has_key?(:presence) && validations[:presence]
validate('presence', validations[:presence], attrs, doc_attrs)
validations.delete(:presence)
end

# Before we run the rest of the validators, lets handle
Expand Down
10 changes: 5 additions & 5 deletions spec/grape/validations/presence_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,23 +114,23 @@ def app
it 'validates triple nested parameters' do
get('/nested_triple')
last_response.status.should == 400
last_response.body.should == '{"error":"missing parameter: admin[admin_name]"}'
last_response.body.should == '{"error":"missing parameter: admin[admin_name], missing parameter: admin[super][user][first_name]"}'

get('/nested_triple', :user => {:first_name => "Billy"})
last_response.status.should == 400
last_response.body.should == '{"error":"missing parameter: admin[admin_name]"}'
last_response.body.should == '{"error":"missing parameter: admin[admin_name], missing parameter: admin[super][user][first_name]"}'

get('/nested_triple', :admin => {:super => {:first_name => "Billy"}})
last_response.status.should == 400
last_response.body.should == '{"error":"missing parameter: admin[admin_name]"}'
last_response.body.should == '{"error":"missing parameter: admin[admin_name], missing parameter: admin[super][user][first_name]"}'

get('/nested_triple', :super => {:user => {:first_name => "Billy", :last_name => "Bob"}})
last_response.status.should == 400
last_response.body.should == '{"error":"missing parameter: admin[admin_name]"}'
last_response.body.should == '{"error":"missing parameter: admin[admin_name], missing parameter: admin[super][user][first_name]"}'

get('/nested_triple', :admin => {:super => {:user => {:first_name => "Billy"}}})
last_response.status.should == 400
last_response.body.should == '{"error":"missing parameter: admin[admin_name]"}'
last_response.body.should == '{"error":"missing parameter: admin[admin_name], missing parameter: admin[super][user][last_name]"}'

get('/nested_triple', :admin => { :admin_name => 'admin', :super => {:user => {:first_name => "Billy"}}})
last_response.status.should == 400
Expand Down
18 changes: 16 additions & 2 deletions spec/grape/validations_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -220,12 +220,26 @@ def app; subject end
end
end

context 'multiple validation errors' do
before do
subject.params { requires :yolo; requires :swag }
subject.get '/two_required' do 'two required works'; end
end

it 'throws the validation errors' do
get '/two_required'
last_response.status.should == 400
last_response.body.should =~ /missing parameter: yolo/
last_response.body.should =~ /missing parameter: swag/
end
end

context 'custom validation' do
module CustomValidations
class Customvalidator < Grape::Validations::Validator
def validate_param!(attr_name, params)
unless params[attr_name] == 'im custom'
throw :error, :status => 400, :message => "#{attr_name}: is not custom!"
raise Grape::Exceptions::Validation, :status => 400, :message => "#{attr_name}: is not custom!"
end
end
end
Expand Down Expand Up @@ -281,7 +295,7 @@ def validate_param!(attr_name, params)
it 'validates when param is not present' do
get '/required_custom'
last_response.status.should == 400
last_response.body.should == 'missing parameter: custom'
last_response.body.should == 'missing parameter: custom, custom: is not custom!'
end

context 'nested namespaces' do
Expand Down

0 comments on commit ff20cd4

Please sign in to comment.