Skip to content

Commit 9f9deaf

Browse files
authored
Merge pull request rails#52605 from Shopify/scope_with_keywords
Use keywords with scopes and resources
2 parents 36f5a20 + f4b581b commit 9f9deaf

File tree

4 files changed

+49
-60
lines changed

4 files changed

+49
-60
lines changed

actionpack/lib/action_dispatch/routing/mapper.rb

Lines changed: 42 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,7 @@ def default_url_options=(options)
673673
alias_method :default_url_options, :default_url_options=
674674

675675
def with_default_scope(scope, &block)
676-
scope(scope) do
676+
scope(**scope) do
677677
instance_exec(&block)
678678
end
679679
end
@@ -883,8 +883,7 @@ module Scoping
883883
# scope as: "sekret" do
884884
# resources :posts
885885
# end
886-
def scope(*args)
887-
options = args.extract_options!.dup
886+
def scope(*args, only: nil, except: nil, **options)
888887
scope = {}
889888

890889
options[:path] = args.flatten.join("/") if args.any?
@@ -905,9 +904,8 @@ def scope(*args)
905904
block, options[:constraints] = options[:constraints], {}
906905
end
907906

908-
if options.key?(:only) || options.key?(:except)
909-
scope[:action_options] = { only: options.delete(:only),
910-
except: options.delete(:except) }
907+
if only || except
908+
scope[:action_options] = { only:, except: }
911909
end
912910

913911
if options.key? :anchor
@@ -987,18 +985,16 @@ def controller(controller)
987985
# namespace :admin, as: "sekret" do
988986
# resources :posts
989987
# end
990-
def namespace(path, options = {}, &block)
991-
path = path.to_s
992-
993-
defaults = {
994-
module: path,
995-
as: options.fetch(:as, path),
996-
shallow_path: options.fetch(:path, path),
997-
shallow_prefix: options.fetch(:as, path)
998-
}
988+
def namespace(name, as: DEFAULT, path: DEFAULT, shallow_path: DEFAULT, shallow_prefix: DEFAULT, **options, &block)
989+
name = name.to_s
990+
options[:module] ||= name
991+
as = name if as == DEFAULT
992+
path = name if path == DEFAULT
993+
shallow_path = path if shallow_path == DEFAULT
994+
shallow_prefix = as if shallow_prefix == DEFAULT
999995

1000-
path_scope(options.delete(:path) { path }) do
1001-
scope(defaults.merge!(options), &block)
996+
path_scope(path) do
997+
scope(**options, as:, shallow_path:, shallow_prefix:, &block)
1002998
end
1003999
end
10041000

@@ -1192,7 +1188,7 @@ module Resources
11921188
class Resource # :nodoc:
11931189
attr_reader :controller, :path, :param
11941190

1195-
def initialize(entities, api_only, shallow, options = {})
1191+
def initialize(entities, api_only, shallow, only: nil, except: nil, **options)
11961192
if options[:param].to_s.include?(":")
11971193
raise ArgumentError, ":param option can't contain colons"
11981194
end
@@ -1205,8 +1201,8 @@ def initialize(entities, api_only, shallow, options = {})
12051201
@options = options
12061202
@shallow = shallow
12071203
@api_only = api_only
1208-
@only = options.delete :only
1209-
@except = options.delete :except
1204+
@only = only
1205+
@except = except
12101206
end
12111207

12121208
def default_actions
@@ -1285,7 +1281,7 @@ def singleton?; false; end
12851281
end
12861282

12871283
class SingletonResource < Resource # :nodoc:
1288-
def initialize(entities, api_only, shallow, options)
1284+
def initialize(entities, api_only, shallow, **options)
12891285
super
12901286
@as = nil
12911287
@controller = (options[:controller] || plural).to_s
@@ -1350,19 +1346,17 @@ def resources_path_names(options)
13501346
#
13511347
# ### Options
13521348
# Takes same options as [resources](rdoc-ref:#resources)
1353-
def resource(*resources, &block)
1354-
options = resources.extract_options!.dup
1355-
1356-
if apply_common_behavior_for(:resource, resources, options, &block)
1349+
def resource(*resources, concerns: nil, **options, &block)
1350+
if apply_common_behavior_for(:resource, resources, concerns:, **options, &block)
13571351
return self
13581352
end
13591353

13601354
with_scope_level(:resource) do
13611355
options = apply_action_options options
1362-
resource_scope(SingletonResource.new(resources.pop, api_only?, @scope[:shallow], options)) do
1356+
resource_scope(SingletonResource.new(resources.pop, api_only?, @scope[:shallow], **options)) do
13631357
yield if block_given?
13641358

1365-
concerns(options[:concerns]) if options[:concerns]
1359+
concerns(*concerns) if concerns
13661360

13671361
new do
13681362
get :new
@@ -1520,19 +1514,17 @@ def resource(*resources, &block)
15201514
#
15211515
# # resource actions are at /admin/posts.
15221516
# resources :posts, path: "admin/posts"
1523-
def resources(*resources, &block)
1524-
options = resources.extract_options!.dup
1525-
1526-
if apply_common_behavior_for(:resources, resources, options, &block)
1517+
def resources(*resources, concerns: nil, **options, &block)
1518+
if apply_common_behavior_for(:resources, resources, concerns:, **options, &block)
15271519
return self
15281520
end
15291521

15301522
with_scope_level(:resources) do
15311523
options = apply_action_options options
1532-
resource_scope(Resource.new(resources.pop, api_only?, @scope[:shallow], options)) do
1524+
resource_scope(Resource.new(resources.pop, api_only?, @scope[:shallow], **options)) do
15331525
yield if block_given?
15341526

1535-
concerns(options[:concerns]) if options[:concerns]
1527+
concerns(*concerns) if concerns
15361528

15371529
collection do
15381530
get :index if parent_resource.actions.include?(:index)
@@ -1617,19 +1609,19 @@ def nested(&block)
16171609
if shallow? && shallow_nesting_depth >= 1
16181610
shallow_scope do
16191611
path_scope(parent_resource.nested_scope) do
1620-
scope(nested_options, &block)
1612+
scope(**nested_options, &block)
16211613
end
16221614
end
16231615
else
16241616
path_scope(parent_resource.nested_scope) do
1625-
scope(nested_options, &block)
1617+
scope(**nested_options, &block)
16261618
end
16271619
end
16281620
end
16291621
end
16301622

16311623
# See ActionDispatch::Routing::Mapper::Scoping#namespace.
1632-
def namespace(path, options = {})
1624+
def namespace(name, as: DEFAULT, path: DEFAULT, shallow_path: DEFAULT, shallow_prefix: DEFAULT, **options, &block)
16331625
if resource_scope?
16341626
nested { super }
16351627
else
@@ -1784,22 +1776,21 @@ def parent_resource
17841776
@scope[:scope_level_resource]
17851777
end
17861778

1787-
def apply_common_behavior_for(method, resources, options, &block)
1779+
def apply_common_behavior_for(method, resources, shallow: nil, **options, &block)
17881780
if resources.length > 1
1789-
resources.each { |r| public_send(method, r, options, &block) }
1781+
resources.each { |r| public_send(method, r, shallow:, **options, &block) }
17901782
return true
17911783
end
17921784

1793-
if options[:shallow]
1794-
options.delete(:shallow)
1795-
shallow do
1796-
public_send(method, resources.pop, options, &block)
1785+
if shallow
1786+
self.shallow do
1787+
public_send(method, resources.pop, **options, &block)
17971788
end
17981789
return true
17991790
end
18001791

18011792
if resource_scope?
1802-
nested { public_send(method, resources.pop, options, &block) }
1793+
nested { public_send(method, resources.pop, shallow:, **options, &block) }
18031794
return true
18041795
end
18051796

@@ -1808,9 +1799,9 @@ def apply_common_behavior_for(method, resources, options, &block)
18081799
end
18091800

18101801
scope_options = options.slice!(*RESOURCE_OPTIONS)
1811-
unless scope_options.empty?
1812-
scope(scope_options) do
1813-
public_send(method, resources.pop, options, &block)
1802+
if !scope_options.empty? || !shallow.nil?
1803+
scope(**scope_options, shallow:) do
1804+
public_send(method, resources.pop, **options, &block)
18141805
end
18151806
return true
18161807
end
@@ -1886,9 +1877,10 @@ def canonical_action?(action)
18861877
end
18871878

18881879
def shallow_scope
1889-
scope = { as: @scope[:shallow_prefix],
1890-
path: @scope[:shallow_path] }
1891-
@scope = @scope.new scope
1880+
@scope = @scope.new(
1881+
as: @scope[:shallow_prefix],
1882+
path: @scope[:shallow_path],
1883+
)
18921884

18931885
yield
18941886
ensure
@@ -2152,8 +2144,7 @@ def concern(name, callable = nil, &block)
21522144
# namespace :posts do
21532145
# concerns :commentable
21542146
# end
2155-
def concerns(*args)
2156-
options = args.extract_options!
2147+
def concerns(*args, **options)
21572148
args.flatten.each do |name|
21582149
if concern = @concerns[name]
21592150
concern.call(self, options)

actionpack/test/controller/resources_test.rb

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def test_multiple_default_restful_routes
7777
def test_multiple_resources_with_options
7878
expected_options = { controller: "threads", action: "index" }
7979

80-
with_restful_routing :messages, :comments, expected_options.slice(:controller) do
80+
with_restful_routing :messages, :comments, controller: "threads" do
8181
assert_recognizes(expected_options, path: "comments")
8282
assert_recognizes(expected_options, path: "messages")
8383
end
@@ -1110,17 +1110,15 @@ def test_singleton_resource_name_is_not_singularized
11101110
end
11111111

11121112
private
1113-
def with_restful_routing(*args)
1114-
options = args.extract_options!
1113+
def with_restful_routing(*args, **options)
11151114
collection_methods = options.delete(:collection)
11161115
member_methods = options.delete(:member)
11171116
path_prefix = options.delete(:path_prefix)
1118-
args.push(options)
11191117

11201118
with_routing do |set|
11211119
set.draw do
11221120
scope(path_prefix || "") do
1123-
resources(*args) do
1121+
resources(*args, **options) do
11241122
if collection_methods
11251123
collection do
11261124
collection_methods.each do |name, method|

actionpack/test/dispatch/routing/concerns_test.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ class ReviewsController < ResourcesController; end
77
class RoutingConcernsTest < ActionDispatch::IntegrationTest
88
class Reviewable
99
def self.call(mapper, options = {})
10-
mapper.resources :reviews, options
10+
mapper.resources :reviews, **options
1111
end
1212
end
1313

1414
Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
1515
app.draw do
1616
concern :commentable do |options|
17-
resources :comments, options
17+
resources :comments, **options
1818
end
1919

2020
concern :image_attachable do

actionpack/test/dispatch/routing_test.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -990,13 +990,13 @@ def test_resources_for_uncountable_names
990990

991991
def test_resource_does_not_modify_passed_options
992992
options = { id: /.+?/, format: /json|xml/ }
993-
draw { resource :user, options }
993+
draw { resource :user, **options }
994994
assert_equal({ id: /.+?/, format: /json|xml/ }, options)
995995
end
996996

997997
def test_resources_does_not_modify_passed_options
998998
options = { id: /.+?/, format: /json|xml/ }
999-
draw { resources :users, options }
999+
draw { resources :users, **options }
10001000
assert_equal({ id: /.+?/, format: /json|xml/ }, options)
10011001
end
10021002

0 commit comments

Comments
 (0)