Skip to content

Commit 864568d

Browse files
namusyakadblock
authored andcommitted
Concatenate parent declared params with current one (#1422)
1 parent 7805dd0 commit 864568d

File tree

4 files changed

+88
-14
lines changed

4 files changed

+88
-14
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
* [#1414](https://github.com/ruby-grape/grape/pull/1414): Fix multiple version definitions for path versioning - [@304](https://github.com/304).
1919
* [#1415](https://github.com/ruby-grape/grape/pull/1415): Fix `declared(params, include_parent_namespaces: false)` - [@304](https://github.com/304).
2020
* [#1421](https://github.com/ruby-grape/grape/pull/1421): Avoid polluting `Grape::Middleware::Error` - [@namusyaka](https://github.com/namusyaka).
21+
* [#1422](https://github.com/ruby-grape/grape/pull/1422): Concat parent declared params with current one - [@plukevdh](https://github.com/plukevdh), [@rnubel](https://github.com/rnubel), [@namusyaka](https://github.com/namusyaka).
2122

2223
0.16.2 (4/12/2016)
2324
==================

lib/grape/api.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,13 @@ def inherited(subclass)
8888
def inherit_settings(other_settings)
8989
top_level_setting.inherit_from other_settings.point_in_time_copy
9090

91+
# Propagate any inherited params down to our endpoints, and reset any
92+
# compiled routes.
93+
endpoints.each do |e|
94+
e.inherit_settings(top_level_setting.namespace_stackable)
95+
e.reset_routes!
96+
end
97+
9198
reset_routes!
9299
end
93100
end

lib/grape/endpoint.rb

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,7 @@ class Endpoint
1414

1515
class << self
1616
def new(*args, &block)
17-
if self == Endpoint
18-
Class.new(Endpoint).new(*args, &block)
19-
else
20-
super
21-
end
17+
self == Endpoint ? Class.new(Endpoint).new(*args, &block) : super
2218
end
2319

2420
def before_each(new_setup = false, &block)
@@ -33,9 +29,7 @@ def before_each(new_setup = false, &block)
3329

3430
def run_before_each(endpoint)
3531
superclass.run_before_each(endpoint) unless self == Endpoint
36-
before_each.each do |blk|
37-
blk.call(endpoint) if blk.respond_to? :call
38-
end
32+
before_each.each { |blk| blk.call(endpoint) if blk.respond_to?(:call) }
3933
end
4034

4135
# @api private
@@ -68,6 +62,18 @@ def generate_api_method(method_name, &block)
6862
end
6963
end
7064

65+
# Create a new endpoint.
66+
# @param new_settings [InheritableSetting] settings to determine the params,
67+
# validations, and other properties from.
68+
# @param options [Hash] attributes of this endpoint
69+
# @option options path [String or Array] the path to this endpoint, within
70+
# the current scope.
71+
# @option options method [String or Array] which HTTP method(s) can be used
72+
# to reach this endpoint.
73+
# @option options route_options [Hash]
74+
# @note This happens at the time of API definition, so in this context the
75+
# endpoint does not know if it will be mounted under a different endpoint.
76+
# @yield a block defining what your API should do when this endpoint is hit
7177
def initialize(new_settings, options = {}, &block)
7278
require_option(options, :path)
7379
require_option(options, :method)
@@ -96,6 +102,20 @@ def initialize(new_settings, options = {}, &block)
96102
@block = self.class.generate_api_method(method_name, &block)
97103
end
98104

105+
# Update our settings from a given set of stackable parameters. Used when
106+
# the endpoint's API is mounted under another one.
107+
def inherit_settings(namespace_stackable)
108+
inheritable_setting.route[:saved_validations] += namespace_stackable[:validations]
109+
parent_declared_params = namespace_stackable[:declared_params]
110+
111+
if parent_declared_params
112+
inheritable_setting.route[:declared_params] ||= []
113+
inheritable_setting.route[:declared_params].concat(parent_declared_params.flatten)
114+
end
115+
116+
endpoints && endpoints.each { |e| e.inherit_settings(namespace_stackable) }
117+
end
118+
99119
def require_option(options, key)
100120
raise Grape::Exceptions::MissingOption.new(key) unless options.key?(key)
101121
end
@@ -284,9 +304,7 @@ def build_stack(helpers)
284304

285305
def build_helpers
286306
helpers = namespace_stackable(:helpers) || []
287-
Module.new do
288-
helpers.each { |mod_to_include| include mod_to_include }
289-
end
307+
Module.new { helpers.each { |mod_to_include| include mod_to_include } }
290308
end
291309

292310
private :build_stack, :build_helpers
@@ -301,9 +319,7 @@ def lazy_initialize!
301319
@lazy_initialize_lock.synchronize do
302320
return true if @lazy_initialized
303321

304-
@helpers = build_helpers.tap do |mod|
305-
self.class.send(:include, mod)
306-
end
322+
@helpers = build_helpers.tap { |mod| self.class.send(:include, mod) }
307323
@app = options[:app] || build_stack(@helpers)
308324

309325
@lazy_initialized = true

spec/grape/endpoint_spec.rb

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,56 @@ def app
532532
end
533533
end
534534

535+
describe '#declared; from a nested mounted endpoint' do
536+
before do
537+
doubly_mounted = Class.new(Grape::API)
538+
doubly_mounted.namespace :more do
539+
params do
540+
requires :y, type: Integer
541+
end
542+
route_param :y do
543+
get do
544+
{
545+
params: params,
546+
declared_params: declared(params)
547+
}
548+
end
549+
end
550+
end
551+
552+
mounted = Class.new(Grape::API)
553+
mounted.namespace :another do
554+
params do
555+
requires :mount_space, type: Integer
556+
end
557+
route_param :mount_space do
558+
mount doubly_mounted
559+
end
560+
end
561+
562+
subject.format :json
563+
subject.namespace :something do
564+
params do
565+
requires :id, type: Integer
566+
end
567+
resource ':id' do
568+
mount mounted
569+
end
570+
end
571+
end
572+
573+
it 'can access parent attributes' do
574+
get '/something/123/another/456/more/789'
575+
expect(last_response.status).to eq 200
576+
json = JSON.parse(last_response.body, symbolize_names: true)
577+
578+
# test all three levels of params
579+
expect(json[:declared_params][:y]).to eq 789
580+
expect(json[:declared_params][:mount_space]).to eq 456
581+
expect(json[:declared_params][:id]).to eq 123
582+
end
583+
end
584+
535585
describe '#params' do
536586
it 'is available to the caller' do
537587
subject.get('/hey') do

0 commit comments

Comments
 (0)