Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extended given to receive a Proc #1443

Merged
merged 1 commit into from
Jul 19, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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