Skip to content

Commit

Permalink
Extended given to receive a Proc (ruby-grape#1443)
Browse files Browse the repository at this point in the history
  • Loading branch information
glaucocustodio authored and dblock committed Jul 19, 2016
1 parent 3802f81 commit c9a81a8
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 3 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
* [#1390](https://github.com/ruby-grape/grape/pull/1390): Allow inserting middleware at arbitrary points in the middleware stack - [@Rosa](https://github.com/Rosa).
* [#1366](https://github.com/ruby-grape/grape/pull/1366): Store `message_key` on `Grape::Exceptions::Validation` - [@mkou](https://github.com/mkou).
* [#1398](https://github.com/ruby-grape/grape/pull/1398): Added `rescue_from :grape_exceptions` - allow Grape to use the built-in `Grape::Exception` handing and use `rescue :all` behavior for everything else - [@mmclead](https://github.com/mmclead).
* [#1443](https://github.com/ruby-grape/grape/pull/1443): Extended `given` to receive a `Proc` - [@glaucocustodio](https://github.com/glaucocustodio).
* Your contribution here.

#### Fixes

* [#1430](https://github.com/ruby-grape/grape/pull/1430): Fix for `declared(params)` inside `route_param` - [@Arkanain](https://github.com/Arkanain).
Expand Down
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,19 @@ params do
end
```

In the example above Grape will use `blank?` to check whether the `shelf_id` param is present.

Given also takes a `Proc` with custom code. Below, the param `description` is required only if the value of `category` is equal `foo`:

```ruby
params do
optional :category
given category: ->(val) { val == 'foo' } do
requires :description
end
end
```

### Built-in Validators

#### `allow_blank`
Expand Down
3 changes: 2 additions & 1 deletion lib/grape/dsl/parameters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ def all_or_none_of(*attrs)
# @yield a parameter definition DSL
def given(*attrs, &block)
attrs.each do |attr|
raise Grape::Exceptions::UnknownParameter.new(attr) unless declared_param?(attr)
attr_ = attr.is_a?(Hash) ? attr.keys[0] : attr
raise Grape::Exceptions::UnknownParameter.new(attr_) unless declared_param?(attr_)
end
new_lateral_scope(dependent_on: attrs, &block)
end
Expand Down
8 changes: 7 additions & 1 deletion lib/grape/validations/params_scope.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,13 @@ def should_validate?(parameters)
any_element_blank?(parameters))

@dependent_on.each do |dependency|
return false if params(parameters).try(:[], dependency).blank?
if dependency.is_a?(Hash)
dependency_key = dependency.keys[0]
proc = dependency.values[0]
return false unless proc.call(params(parameters).try(:[], dependency_key))
elsif params(parameters).try(:[], dependency).blank?
return false
end
end if @dependent_on

return true if parent.nil?
Expand Down
87 changes: 87 additions & 0 deletions spec/grape/validations/params_scope_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -405,4 +405,91 @@ def initialize(value)
expect(JSON.parse(last_response.body)).to eq('bar' => { 'a' => 'true', 'c' => { 'b' => 'yes' } })
end
end

context 'when validations are dependent on a parameter with specific value' do
before do
subject.params do
optional :a
given a: ->(val) { val == 'x' } do
requires :b
end
end
subject.get('/test') { declared(params).to_json }
end

it 'applies the validations only if the parameter has the specific value' do
get '/test'
expect(last_response.status).to eq(200)

get '/test', a: 'x'
expect(last_response.status).to eq(400)
expect(last_response.body).to eq('b is missing')

get '/test', a: 'x', b: true
expect(last_response.status).to eq(200)
end

it 'raises an error if the dependent parameter was never specified' do
expect do
subject.params do
given :c do
end
end
end.to raise_error(Grape::Exceptions::UnknownParameter)
end

it 'includes the parameter within #declared(params)' do
get '/test', a: true, b: true

expect(JSON.parse(last_response.body)).to eq('a' => 'true', 'b' => 'true')
end

it 'returns a sensible error message within a nested context' do
subject.params do
requires :bar, type: Hash do
optional :a
given a: ->(val) { val == 'x' } do
requires :b
end
end
end
subject.get('/nested') { 'worked' }

get '/nested', bar: { a: 'x' }
expect(last_response.status).to eq(400)
expect(last_response.body).to eq('bar[b] is missing')
end

it 'includes the nested parameter within #declared(params)' do
subject.params do
requires :bar, type: Hash do
optional :a
given a: ->(val) { val == 'x' } do
requires :b
end
end
end
subject.get('/nested') { declared(params).to_json }

get '/nested', bar: { a: 'x', b: 'yes' }
expect(JSON.parse(last_response.body)).to eq('bar' => { 'a' => 'x', 'b' => 'yes' })
end

it 'includes level 2 nested parameters outside the given within #declared(params)' do
subject.params do
requires :bar, type: Hash do
optional :a
given a: ->(val) { val == 'x' } do
requires :c, type: Hash do
requires :b
end
end
end
end
subject.get('/nested') { declared(params).to_json }

get '/nested', bar: { a: 'x', c: { b: 'yes' } }
expect(JSON.parse(last_response.body)).to eq('bar' => { 'a' => 'x', 'c' => { 'b' => 'yes' } })
end
end
end

0 comments on commit c9a81a8

Please sign in to comment.