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

Allow to have both Rails and Rage controllers in one application #83

Merged
merged 2 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 21 additions & 23 deletions lib/rage-rb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,25 @@

module Rage
def self.application
Application.new(__router)
app = Application.new(__router)

config.middleware.middlewares.reverse.inject(app) do |next_in_chain, (middleware, args, block)|
# in Rails compatibility mode we first check if the middleware is a part of the Rails middleware stack;
# if it is - it is expected to be built using `ActionDispatch::MiddlewareStack::Middleware#build`
if Rage.config.internal.rails_mode
rails_middleware = Rails.application.config.middleware.middlewares.find { |m| m.name == middleware.name }
end

if rails_middleware
rails_middleware.build(next_in_chain)
else
middleware.new(next_in_chain, *args, &block)
end
end
end

def self.multi_application
Rage::Router::Util::Cascade.new(application, Rails.application)
end

def self.routes
Expand Down Expand Up @@ -43,28 +61,8 @@ def self.logger
@logger ||= config.logger
end

def self.load_middlewares(rack_builder)
config.middleware.middlewares.each do |middleware, args, block|
# in Rails compatibility mode we first check if the middleware is a part of the Rails middleware stack;
# if it is - it is expected to be built using `ActionDispatch::MiddlewareStack::Middleware#build`, but Rack
# expects the middleware to respond to `#new`, so we wrap the middleware into a helper module
if Rage.config.internal.rails_mode
rails_middleware = Rails.application.config.middleware.middlewares.find { |m| m.name == middleware.name }
if rails_middleware
wrapper = Module.new do
extend self
attr_accessor :middleware
def new(app, *, &)
middleware.build(app)
end
end
wrapper.middleware = rails_middleware
middleware = wrapper
end
end

rack_builder.use(middleware, *args, &block)
end
def self.load_middlewares(_)
puts "`Rage.load_middlewares` is deprecated and has been merged into `Rage.application`. Please remove this call."
end

def self.code_loader
Expand Down
14 changes: 10 additions & 4 deletions lib/rage/router/backend.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,18 @@ def on(method, path, handler, constraints: {}, defaults: nil)
raise "Invalid route handler format, expected to match the 'controller#action' pattern" unless handler =~ STRING_HANDLER_REGEXP

controller, action = Rage::Router::Util.path_to_class($1), $2
run_action_method_name = controller.__register_action(action.to_sym)

meta[:controller] = $1
meta[:action] = $2
if controller.ancestors.include?(RageController::API)
run_action_method_name = controller.__register_action(action.to_sym)

handler = eval("->(env, params) { #{controller}.new(env, params).#{run_action_method_name} }")
meta[:controller] = $1
meta[:action] = $2

handler = eval("->(env, params) { #{controller}.new(env, params).#{run_action_method_name} }")
else
# this is a Rails controller; notify `Rage::Router::Util::Cascade` to forward the request to Rails
handler = ->(_, _) { [404, { "X-Cascade" => "pass" }, []] }
end
else
raise "Non-string route handler should respond to `call`" unless handler.respond_to?(:call)
# while regular handlers are expected to be called with the `env` and `params` objects,
Expand Down
15 changes: 15 additions & 0 deletions lib/rage/router/util.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,19 @@ def path_to_name(str)
end
end
end

# @private
class Cascade
def initialize(rage_app, rails_app)
@rage_app = rage_app
@rails_app = rails_app
end

def call(env)
result = @rage_app.call(env)
return result if result[0] == :__http_defer__ || result[1]["X-Cascade".freeze] != "pass".freeze

@rails_app.call(env)
end
end
end
1 change: 0 additions & 1 deletion lib/rage/templates/config.ru
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
require_relative "config/application"

run Rage.application
Rage.load_middlewares(self)
1 change: 0 additions & 1 deletion spec/integration/test_app/config.ru
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
require_relative "config/application"

run Rage.application
Rage.load_middlewares(self)
1 change: 0 additions & 1 deletion spec/rspec/config.ru
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
run Rage.application
Rage.load_middlewares(self)
Loading