Skip to content

Commit

Permalink
fix(ruby-grape#1922): Updating UPGRADING and README files explaining …
Browse files Browse the repository at this point in the history
…the instance variables behavior. Extra tests added
  • Loading branch information
jcagarcia committed Nov 23, 2023
1 parent 7486d3c commit cef14da
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 20 deletions.
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@
- [Current Route and Endpoint](#current-route-and-endpoint)
- [Before, After and Finally](#before-after-and-finally)
- [Anchoring](#anchoring)
- [Instance Variables](#instance-variables)
- [Using Custom Middleware](#using-custom-middleware)
- [Grape Middleware](#grape-middleware)
- [Rails Middleware](#rails-middleware)
Expand Down Expand Up @@ -3595,6 +3596,42 @@ end
This will match all paths starting with '/statuses/'. There is one caveat though: the `params[:status]` parameter only holds the first part of the request url.
Luckily this can be circumvented by using the described above syntax for path specification and using the `PATH_INFO` Rack environment variable, using `env['PATH_INFO']`. This will hold everything that comes after the '/statuses/' part.

## Instance Variables

You can use instance variables to pass information across the various stages of a request. An instance variable set within a `before` validator is accessible within the endpoint's code and can also be utilized within the `rescue_from` handler.

```ruby
class TwitterAPI < Grape::API
before do
@var = 1
end

get '/' do
puts @var # => 1
raise
end

rescue_from :all do
puts @var # => 1
end
end
```

The values of instance variables cannot be shared among various endpoints within the same API. This limitation arises due to Grape generating a new instance for each request made. Consequently, instance variables set within an endpoint during one request differ from those set during a subsequent request, as they exist within separate instances.

```ruby
class TwitterAPI < Grape::API
get '/first' do
@var = 1
puts @var # => 1
end

get '/second' do
puts @var # => nil
end
end
```

## Using Custom Middleware

### Grape Middleware
Expand Down
8 changes: 7 additions & 1 deletion UPGRADING.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
Upgrading Grape
===============

### Upgrading to >= 2.0.1
### Upgrading to >= 2.1.0

#### Grape::Router::Route.route_xxx methods have been removed

- `route_method` is accessible through `request_method`
- `route_path` is accessible through `path`
- Any other `route_xyz` are accessible through `options[xyz]`

#### Instance variables scope

Due to the changes done in [#2377](https://github.com/ruby-grape/grape/pull/2377), the instance variables defined inside each of the endpoints (or inside a `before` validator) are now accessible inside the `rescue_from`. This means the scope of the instance variables has changed.

If you were using the same variable name defined inside an endpoint or `before` validator inside a `rescue_from` handler, you need to take in mind that you can start getting different values or you can be overriding values.

### Upgrading to >= 2.0.0

#### Headers
Expand Down
76 changes: 57 additions & 19 deletions spec/grape/api_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2130,25 +2130,6 @@ class CustomError < Grape::Exceptions::Base; end
expect(last_response.status).to be 500
expect(last_response.body).to eql 'Invalid response'
end

context 'when using instance variables inside the rescue_from' do
it 'is able to access the values' do
expected_instance_variable_value = 'wadus'

subject.rescue_from(:all) do
body = { my_var: @my_var }
error!(body, 400)
end
subject.get('/') do
@my_var = expected_instance_variable_value
raise
end

get '/'
expect(last_response.status).to be 400
expect(last_response.body).to eq({ my_var: expected_instance_variable_value }.to_json)
end
end
end

describe '.rescue_from klass, block' do
Expand Down Expand Up @@ -4371,4 +4352,61 @@ def uniqe_id_route
expect(last_response.body).to be_eql('1-2')
end
end

context 'instance variables' do
context 'when setting instance variables in a before validation' do
it 'is accessible inside the endpoint' do
expected_instance_variable_value = 'wadus'

subject.before do
@my_var = expected_instance_variable_value
end

subject.get('/') do
{ my_var: @my_var }.to_json
end

get '/'
expect(last_response.body).to eq({ my_var: expected_instance_variable_value }.to_json)
end
end

context 'when setting instance variables inside the endpoint code' do
it 'is accessible inside the rescue_from handler' do
expected_instance_variable_value = 'wadus'

subject.rescue_from(:all) do
body = { my_var: @my_var }
error!(body, 400)
end

subject.get('/') do
@my_var = expected_instance_variable_value
raise
end

get '/'
expect(last_response.status).to be 400
expect(last_response.body).to eq({ my_var: expected_instance_variable_value }.to_json)
end

it 'is NOT available in other endpoints of the same api' do
expected_instance_variable_value = 'wadus'

subject.get('/first') do
@my_var = expected_instance_variable_value
{ my_var: @my_var }.to_json
end

subject.get('/second') do
{ my_var: @my_var }.to_json
end

get '/first'
expect(last_response.body).to eq({ my_var: expected_instance_variable_value }.to_json)
get '/second'
expect(last_response.body).to eq({ my_var: nil }.to_json)
end
end
end
end

0 comments on commit cef14da

Please sign in to comment.