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

Reload routes when changed #501

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
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
11 changes: 7 additions & 4 deletions lib/ruby_lsp/ruby_lsp_rails/addon.rb
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,13 @@ def create_definition_listener(response_builder, uri, node_context, dispatcher)

sig { params(changes: T::Array[{ uri: String, type: Integer }]).void }
def workspace_did_change_watched_files(changes)
if changes.any? do |change|
change[:uri].end_with?("db/schema.rb") || change[:uri].end_with?("structure.sql")
end
schema = lambda { |change| change[:uri].end_with?("db/schema.rb") || change[:uri].end_with?("structure.sql") }
routes = lambda { |change| change[:uri].end_with?("routes.rb") || change[:uri].match?("routes/**/*.rb") }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored to simplify the conditional.


if changes.any?(&schema)
@rails_runner_client.trigger_reload
elsif changes.any?(&routes)
@rails_runner_client.reload_routes
end
end

Expand All @@ -141,7 +144,7 @@ def register_additional_file_watchers(global_state:, outgoing_queue:)
register_options: Interface::DidChangeWatchedFilesRegistrationOptions.new(
watchers: [
Interface::FileSystemWatcher.new(
glob_pattern: "**/*structure.sql",
glob_pattern: "**/*structure.sql,**/*routes.rb,routes/**/*.rb",
Copy link
Contributor Author

@andyw8 andyw8 Nov 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should cover almost any way that people set up the Rails routes, but there is a risk of a false positive if someone is using the term routes for something else in their app.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 but I wonder if we can ask Rails where all the routes files are...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly:

dummy(dev)> Rails.application.routes.draw_paths.map(&:to_s)
=> 
["/Users/andyw8/.gem/ruby/3.3.0/gems/actionview-8.0.0.beta1/config/routes",
 "/Users/andyw8/.gem/ruby/3.3.0/gems/activestorage-8.0.0.beta1/config/routes",
 "/Users/andyw8/.gem/ruby/3.3.0/gems/actioncable-8.0.0.beta1/config/routes",
 "/Users/andyw8/.gem/ruby/3.3.0/gems/actionmailbox-8.0.0.beta1/config/routes",
 "/Users/andyw8/.gem/ruby/3.3.0/gems/actiontext-8.0.0.beta1/config/routes",
 "/Users/andyw8/src/github.com/Shopify/ruby-lsp-rails/test/dummy/config/routes",
 "/Users/andyw8/src/github.com/Shopify/ruby-lsp-rails/test/dummy/config/routes"]

kind: Constant::WatchKind::CREATE | Constant::WatchKind::CHANGE | Constant::WatchKind::DELETE,
),
],
Expand Down
12 changes: 12 additions & 0 deletions lib/ruby_lsp/ruby_lsp_rails/runner_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,18 @@ def trigger_reload
nil
end

sig { void }
def reload_routes
log_message("Reloading Rails routes")
send_notification("reload_routes")
rescue IncompleteMessageError
log_message(
"Ruby LSP Rails failed to reload routes",
type: RubyLsp::Constant::MessageType::ERROR,
)
nil
end

sig { void }
def shutdown
log_message("Ruby LSP Rails shutting down server")
Expand Down
2 changes: 2 additions & 0 deletions lib/ruby_lsp/ruby_lsp_rails/server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ def execute(request, params)
send_message(resolve_association_target(params))
when "reload"
::Rails.application.reloader.reload!
when "reload_routes"
::Rails.application.routes_reloader.execute
when "route_location"
send_message(route_location(params.fetch(:name)))
when "route_info"
Expand Down
28 changes: 26 additions & 2 deletions test/ruby_lsp_rails/server_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,34 @@ def resolve_route_info(requirements)
assert_equal("Hello\n", stderr)
end

test "reloads if routes files change" do
old_routes = File.read("test/dummy/config/routes.rb")

@server.execute("route_location", { name: "user_path" })
location = response[:result][:location]
assert_match(%r{test/dummy/config/routes.rb:5$}, location)

File.write("test/dummy/config/routes.rb", <<~RUBY)
Rails.application.routes.draw do
end
RUBY

@server.execute("reload_routes", {})

@server.execute("route_location", { name: "user_path" })

assert_nil(response[:result])
ensure
File.write("test/dummy/config/routes.rb", old_routes)
end

private

def response
_headers, content = @stdout.string.split("\r\n\r\n")
Copy link
Contributor Author

@andyw8 andyw8 Nov 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had to change to handle making multiple requests.

JSON.parse(content, symbolize_names: true)
headers, content = @stdout.string.split("\r\n\r\n")
content_length = headers[/Content-Length: (\d+)/i, 1].to_i
# binding.break
Copy link
Contributor Author

@andyw8 andyw8 Nov 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vinistock I'm trying to figure out what's happening here: If I add the breakpoint, and call @stdout.string = "" each time, it passes. But I call it from the code it fails with not opened for writing (IOError).

# @stdout.string = ""
JSON.parse(content.first(content_length), symbolize_names: true)
end
end
Loading