Skip to content

Commit 9a93844

Browse files
committed
Add :only and :except to controllers MiddlewareStack. This allows
you to do the following: class PostsController < ApplicationController use AutheMiddleware, :except => [:index, :show] end
1 parent 0078df6 commit 9a93844

File tree

3 files changed

+71
-18
lines changed

3 files changed

+71
-18
lines changed

actionpack/lib/action_controller/metal.rb

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,48 @@
11
require 'active_support/core_ext/class/attribute'
2+
require 'active_support/core_ext/object/blank'
3+
require 'action_dispatch/middleware/stack'
24

35
module ActionController
6+
# Extend ActionDispatch middleware stack to make it aware of options
7+
# allowing the following syntax in controllers:
8+
#
9+
# class PostsController < ApplicationController
10+
# use AuthenticationMiddleware, :except => [:index, :show]
11+
# end
12+
#
13+
class MiddlewareStack < ActionDispatch::MiddlewareStack #:nodoc:
14+
class Middleware < ActionDispatch::MiddlewareStack::Middleware #:nodoc:
15+
def initialize(klass, *args)
16+
options = args.extract_options!
17+
@only = Array(options.delete(:only)).map(&:to_s)
18+
@except = Array(options.delete(:except)).map(&:to_s)
19+
args << options unless options.empty?
20+
super
21+
end
22+
23+
def valid?(action)
24+
if @only.present?
25+
@only.include?(action)
26+
elsif @except.present?
27+
!@except.include?(action)
28+
else
29+
true
30+
end
31+
end
32+
end
33+
34+
def build(action, app=nil, &block)
35+
app ||= block
36+
action = action.to_s
37+
raise "MiddlewareStack#build requires an app" unless app
38+
39+
reverse.inject(app) do |a, middleware|
40+
middleware.valid?(action) ?
41+
middleware.build(a) : a
42+
end
43+
end
44+
end
45+
446
# ActionController::Metal provides a way to get a valid Rack application from a controller.
547
#
648
# In AbstractController, dispatching is triggered directly by calling #process on a new controller.
@@ -91,10 +133,10 @@ def to_a
91133
end
92134

93135
class_attribute :middleware_stack
94-
self.middleware_stack = ActionDispatch::MiddlewareStack.new
136+
self.middleware_stack = ActionController::MiddlewareStack.new
95137

96138
def self.inherited(base)
97-
self.middleware_stack = base.middleware_stack.dup
139+
base.middleware_stack = self.middleware_stack.dup
98140
super
99141
end
100142

@@ -120,7 +162,7 @@ def self.call(env)
120162
# ==== Returns
121163
# Proc:: A rack application
122164
def self.action(name, klass = ActionDispatch::Request)
123-
middleware_stack.build do |env|
165+
middleware_stack.build(name.to_s) do |env|
124166
new.dispatch(name, klass.new(env))
125167
end
126168
end

actionpack/lib/action_dispatch/middleware/stack.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def initialize(*args, &block)
5555

5656
def insert(index, *args, &block)
5757
index = self.index(index) unless index.is_a?(Integer)
58-
middleware = Middleware.new(*args, &block)
58+
middleware = self.class::Middleware.new(*args, &block)
5959
super(index, middleware)
6060
end
6161

@@ -73,7 +73,7 @@ def swap(target, *args, &block)
7373
end
7474

7575
def use(*args, &block)
76-
middleware = Middleware.new(*args, &block)
76+
middleware = self.class::Middleware.new(*args, &block)
7777
push(middleware)
7878
end
7979

@@ -82,8 +82,8 @@ def active
8282
"was removed from the middleware stack", caller
8383
end
8484

85-
def build(app = nil, &blk)
86-
app ||= blk
85+
def build(app = nil, &block)
86+
app ||= block
8787
raise "MiddlewareStack#build requires an app" unless app
8888
reverse.inject(app) { |a, e| e.build(a) }
8989
end

actionpack/test/controller/new_base/middleware_test.rb

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ def call(env)
2828

2929
class MyController < ActionController::Metal
3030
use MyMiddleware
31-
3231
middleware.insert_before MyMiddleware, ExclaimerMiddleware
3332

3433
def index
@@ -39,8 +38,23 @@ def index
3938
class InheritedController < MyController
4039
end
4140

42-
module MiddlewareTests
43-
extend ActiveSupport::Testing::Declarative
41+
class ActionsController < ActionController::Metal
42+
use MyMiddleware, :only => :show
43+
middleware.insert_before MyMiddleware, ExclaimerMiddleware, :except => :index
44+
45+
def index
46+
self.response_body = "index"
47+
end
48+
49+
def show
50+
self.response_body = "show"
51+
end
52+
end
53+
54+
class TestMiddleware < ActiveSupport::TestCase
55+
def setup
56+
@app = MyController.action(:index)
57+
end
4458

4559
test "middleware that is 'use'd is called as part of the Rack application" do
4660
result = @app.call(env_for("/"))
@@ -52,13 +66,13 @@ module MiddlewareTests
5266
result = @app.call(env_for("/"))
5367
assert_equal "First!", result[1]["Middleware-Order"]
5468
end
55-
end
5669

57-
class TestMiddleware < ActiveSupport::TestCase
58-
include MiddlewareTests
70+
test "middleware stack accepts only and except as options" do
71+
result = ActionsController.action(:show).call(env_for("/"))
72+
assert_equal "First!", result[1]["Middleware-Order"]
5973

60-
def setup
61-
@app = MyController.action(:index)
74+
result = ActionsController.action(:index).call(env_for("/"))
75+
assert_nil result[1]["Middleware-Order"]
6276
end
6377

6478
def env_for(url)
@@ -70,8 +84,5 @@ class TestInheritedMiddleware < TestMiddleware
7084
def setup
7185
@app = InheritedController.action(:index)
7286
end
73-
74-
test "middleware inherits" do
75-
end
7687
end
7788
end

0 commit comments

Comments
 (0)