Skip to content

Commit 637b911

Browse files
committed
Use middleware instead Rails controller for model query
- By using middleware instead of a Rails controller, it skips many middlewares that aren't needed for our model query request. In big Rails apps, this could be a big performance improvement. - Although Rails engine also supports being used as a middleware, it still requires registering routes to the application. That doesn't always work depends on the app's own rules on how to register routes. - Compare to Rails engine, middleware is a more flexible way to integrate with Rails apps and also a lot lighter.
1 parent d57d17c commit 637b911

File tree

21 files changed

+89
-160
lines changed

21 files changed

+89
-160
lines changed

Gemfile.lock

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ GEM
206206
sorbet (0.5.10782)
207207
sorbet-static (= 0.5.10782)
208208
sorbet-runtime (0.5.10782)
209+
sorbet-static (0.5.10782-universal-darwin-21)
209210
sorbet-static (0.5.10782-universal-darwin-22)
210211
sorbet-static (0.5.10782-x86_64-linux)
211212
sorbet-static-and-runtime (0.5.10782)
@@ -246,6 +247,7 @@ GEM
246247
zeitwerk (2.6.7)
247248

248249
PLATFORMS
250+
arm64-darwin-21
249251
arm64-darwin-22
250252
x86_64-linux
251253

app/assets/config/ruby_lsp_rails_manifest.js

Lines changed: 0 additions & 1 deletion
This file was deleted.

app/assets/images/rails_ruby_lsp_rails/.keep

Whitespace-only changes.

app/assets/stylesheets/ruby_lsp_rails/application.css

Lines changed: 0 additions & 15 deletions
This file was deleted.

app/controllers/concerns/.keep

Whitespace-only changes.

app/controllers/ruby_lsp/rails/application_controller.rb

Lines changed: 0 additions & 9 deletions
This file was deleted.

app/controllers/ruby_lsp/rails/models_controller.rb

Lines changed: 0 additions & 32 deletions
This file was deleted.

app/jobs/ruby_lsp_rails/application_job.rb

Lines changed: 0 additions & 7 deletions
This file was deleted.

app/mailers/ruby_lsp_rails/application_mailer.rb

Lines changed: 0 additions & 9 deletions
This file was deleted.

app/models/concerns/.keep

Whitespace-only changes.

app/models/ruby_lsp/rails/application_record.rb

Lines changed: 0 additions & 10 deletions
This file was deleted.

app/views/layouts/ruby_lsp_rails/application.html.erb

Lines changed: 0 additions & 15 deletions
This file was deleted.

config/routes.rb

Lines changed: 0 additions & 6 deletions
This file was deleted.

lib/ruby-lsp-rails.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
require "sorbet-runtime"
55
require "ruby_lsp_rails/version"
6-
require "ruby_lsp_rails/engine"
6+
require "ruby_lsp_rails/railtie"
77

88
module RubyLSP
99
module Rails

lib/ruby_lsp_rails/engine.rb

Lines changed: 0 additions & 30 deletions
This file was deleted.

lib/ruby_lsp_rails/middleware.rb

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# typed: strict
2+
# frozen_string_literal: true
3+
4+
module RubyLsp
5+
module Rails
6+
class Middleware
7+
extend T::Sig
8+
9+
PATH_REGEXP = %r{/ruby_lsp_rails/models/(?<model_name>.+)}
10+
11+
sig { params(app: T.untyped).void }
12+
def initialize(app)
13+
@app = app
14+
end
15+
16+
sig { params(env: T::Hash[T.untyped, T.untyped]).returns(T::Array[T.untyped]) }
17+
def call(env)
18+
request = ActionDispatch::Request.new(env)
19+
# TODO: improve the model name regex
20+
match = request.path.match(PATH_REGEXP)
21+
22+
if match
23+
resolve_database_info_from_model(match[:model_name])
24+
else
25+
@app.call(env)
26+
end
27+
rescue
28+
@app.call(env)
29+
end
30+
31+
private
32+
33+
sig { params(model_name: String).returns(T::Array[T.untyped]) }
34+
def resolve_database_info_from_model(model_name)
35+
const = ActiveSupport::Inflector.safe_constantize(model_name)
36+
37+
if const && const < ActiveRecord::Base
38+
begin
39+
schema_file = ActiveRecord::Tasks::DatabaseTasks.schema_dump_path(const.connection.pool.db_config)
40+
rescue => e
41+
warn("Could not locate schema: #{e.message}")
42+
end
43+
44+
body = JSON.dump({
45+
columns: const.columns.map { |column| [column.name, column.type] },
46+
schema_file: schema_file,
47+
})
48+
49+
[200, { "Content-Type" => "application/json" }, [body]]
50+
else
51+
not_found
52+
end
53+
end
54+
55+
sig { returns(T::Array[T.untyped]) }
56+
def not_found
57+
[404, { "Content-Type" => "text/plain" }, ["Not Found"]]
58+
end
59+
end
60+
end
61+
end

lib/ruby_lsp_rails/railtie.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# typed: strict
2+
# frozen_string_literal: true
3+
4+
require "ruby_lsp_rails/middleware"
5+
6+
module RubyLsp
7+
module Rails
8+
class Railtie < ::Rails::Railtie
9+
initializer "ruby_lsp_rails.setup" do |app|
10+
app.config.middleware.insert_after(ActionDispatch::ShowExceptions, RubyLsp::Rails::Middleware)
11+
12+
config.after_initialize do |_app|
13+
if defined?(::Rails::Server)
14+
ssl_enable, host, port = ::Rails::Server::Options.new.parse!(ARGV).values_at(:SSLEnable, :Host, :Port)
15+
app_uri = "#{ssl_enable ? "https" : "http"}://#{host}:#{port}"
16+
File.write("#{::Rails.root}/tmp/app_uri.txt", app_uri)
17+
end
18+
end
19+
end
20+
end
21+
end
22+
end

sorbet/rbi/shims/actiondispatch.rbi

Lines changed: 0 additions & 9 deletions
This file was deleted.

sorbet/rbi/shims/rails.rbi

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,3 @@ module Rails
1818
def configure(&block); end
1919
end
2020
end
21-
22-
module RubyLsp
23-
module Rails
24-
class Engine
25-
class << self
26-
sig { returns(ActionDispatch::Routing::RouteSet) }
27-
def routes; end
28-
end
29-
end
30-
end
31-
end

test/controllers/.keep

Whitespace-only changes.

test/controllers/ruby_lsp_rails/models_controller_test.rb renamed to test/lib/middleware_test.rb

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,8 @@
66
module RubyLsp
77
module Rails
88
class ModelsControllerTest < ActionDispatch::IntegrationTest
9-
T.unsafe(self).include(Engine.routes.url_helpers)
10-
119
test "GET show returns column information for existing models" do
12-
get model_url(model: "User")
10+
get "/ruby_lsp_rails/models/User"
1311
assert_response(:success)
1412
assert_equal(
1513
{
@@ -28,12 +26,12 @@ class ModelsControllerTest < ActionDispatch::IntegrationTest
2826
end
2927

3028
test "GET show returns not_found if model doesn't exist" do
31-
get model_url(model: "NonExistentModel")
29+
get "/ruby_lsp_rails/models/Foo"
3230
assert_response(:not_found)
3331
end
3432

3533
test "GET show returns not_found if class is not a model" do
36-
get model_url(model: "ApplicationJob")
34+
get "/ruby_lsp_rails/models/ApplicationJob"
3735
assert_response(:not_found)
3836
end
3937
end

0 commit comments

Comments
 (0)