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

Add the ability for parameter values to accept a Proc #558

Closed
wants to merge 9 commits into from
Closed
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Next Release
============

#### Features

* [#558](https://github.com/intridea/grape/pull/558): Support lambda-based values for params - [@wpschallenger](https://github.com/wpschallenger)
* [#510](https://github.com/intridea/grape/pull/510): Support lambda-based default values for params - [@myitcv](https://github.com/myitcv).
* [#511](https://github.com/intridea/grape/pull/511): Added `required` option for OAuth2 middleware - [@bcm](https://github.com/bcm).
* [#520](https://github.com/intridea/grape/pull/520): Use `default_error_status` to specify the default status code returned from `error!` - [@salimane](https://github.com/salimane).
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,15 @@ params do
end
```

The :values option can also be supplied with a Proc to be evalutated at runtime, for example given a status
model you may want to restrict by hashtags that you have previously defined in the HashTag model.

```ruby
params do
required :hashtag, type: String, values: -> { Hashtag.all.map{|ht| ht.tag} }
end
```

Parameters can be nested using `group` or by calling `requires` or `optional` with a block.
In the above example, this means `params[:media][:url]` is required along with `params[:id]`,
and `params[:audio][:format]` is required only if `params[:audio]` is present.
Expand Down
6 changes: 5 additions & 1 deletion lib/grape/validations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,10 @@ def configure_declared_params
def validates(attrs, validations)
doc_attrs = { required: validations.keys.include?(:presence) }

values = validations[:values]
values = (values.is_a?(Proc) ? values.call : values)
validations[:values] = doc_attrs[:values] = values if values

# special case (type = coerce)
validations[:coerce] = validations.delete(:type) if validations.key?(:type)

Expand All @@ -212,7 +216,7 @@ def validates(attrs, validations)
end

# type should be compatible with values array, if both exist
if coerce_type && values && values.any? { |v| !v.instance_of?(coerce_type) }
if coerce_type && values && (values.is_a?(Proc) ? values.call : values).any? { |v| !v.instance_of?(coerce_type) }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Values are evaluated above.

raise Grape::Exceptions::IncompatibleOptionValues.new(:type, coerce_type, :values, values)
end

Expand Down
2 changes: 1 addition & 1 deletion lib/grape/validations/values.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module Grape
module Validations
class ValuesValidator < Validator
def initialize(attrs, options, required, scope)
@values = options
@values = (options.is_a?(Proc) ? options.call : options)
@required = required
super
end
Expand Down
19 changes: 19 additions & 0 deletions spec/grape/validations/values_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ class API < Grape::API
get '/default/valid' do
{ type: params[:type] }
end

params do
optional :type, values: -> { ['valid-type1', 'valid-type2', 'valid-type3'] }, default: 'valid-type2'
end
get '/lambda' do
{ type: params[:type] }
end
end
end
end
Expand Down Expand Up @@ -52,6 +59,18 @@ def app
last_response.body.should eq({ type: "valid-type2" }.to_json)
end

it 'allows a proc for values' do
get('/lambda', type: 'valid-type1')
last_response.status.should eq 200
last_response.body.should eq({ type: "valid-type1" }.to_json)
end

it 'does not allow an invalid value for a parameter using lambda' do
get("/lambda", type: 'invalid-type')
last_response.status.should eq 400
last_response.body.should eq({ error: "type does not have a valid value" }.to_json)
end

it 'raises IncompatibleOptionValues on an invalid default value' do
subject = Class.new(Grape::API)
expect {
Expand Down