Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

View your Routes without waiting on Rake #6461

Merged
merged 2 commits into from

8 participants

@schneems
Collaborator

Bring the functionality of Sextant natively to Rails 4. Rather than having to initialize your Rails application ever time you run $ rake routes we can utilize the currently running server to generate routes in much less time. To view routes go to /rails/info/routes, the section in <pre> will match $ rake routes

cc/ @pixeltrix

@josevalim
Owner
@josevalim
Owner
@schneems
Collaborator

@josevalim removed ## on comment and moved to separate methods in the InfoController to get rid of the case statement. Let me know if there is anything else.

@arunagw
Collaborator

Also please squash these commits into smaller number. May be 1-2.

railties/lib/rails/application/route_inspector.rb
@@ -59,6 +59,20 @@ def engine?
end
end
+ # This class is just used for displaying route information
+ # People should not use this class.
+ class RoutePresenter # :nodoc:
+ def self.display_routes(routes = all_routes)
+ inspector = Rails::Application::RouteInspector.new
+ inspector.format(routes, ENV['CONTROLLER']).join "\n"
+ end
+
+ def self.all_routes
+ Rails.application.reload_routes!
@pixeltrix Owner

Do we need to reload routes? They're reloaded on every request in development mode so are unlikely to be stale.

@schneems Collaborator

I just tested this out, can confirm that reload is not needed, it can also be removed from the $ rake routes task as well, I can save that for another PR, or add on another commit here if you like

@pixeltrix Owner

Keep the rake routes change for another pull request - just in case there's reason it's there it'll be easier to revert.

BTW, thanks for your work this. :clap:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
railties/lib/rails/info_controller.rb
((12 lines not shown))
def properties
- if consider_all_requests_local? || request.local?
- render :inline => Rails::Info.to_html
- else
- render :text => '<p>For security purposes, this information is only available to local requests.</p>', :status => :forbidden
- end
+ @info = Rails::Info.to_html
+ render "templates/properties", :layout => 'layout'
@pixeltrix Owner

I'd prefer a templates directory within rails and then use the standard layouts/application and info/:action - that way if we add anything other than InfoController it can use the same directory structure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
railties/test/rails_info_controller_test.rb
@@ -34,7 +35,7 @@ def setup
test "info controller allows requests when all requests are considered local" do
@request.stubs(:local? => false)
- @controller.stubs(:consider_all_requests_local? => true)
+ Rails.application.config.stubs(:consider_all_requests_local => true)
@pixeltrix Owner

I'd prefer to keep the controller method so we can stub it directly in these tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@jeremy
Owner

Hot. Happy to see more like this available in dev.

@schneems
Collaborator

Squashed everything into two commits, removed the reload code, updated the controller stubs in the tests, moved views under rails/templates, if we want to encourage more of this type of functionality, I would suggest making a full blown app/ dir in rails/ and putting the controller in rails/app/controllers etc.

railties/lib/rails/application/route_inspector.rb
@@ -59,6 +59,19 @@ def engine?
end
end
+ # This class is just used for displaying route information
+ # People should not use this class.
+ class RoutePresenter # :nodoc:
+ def self.display_routes(routes = all_routes)
+ inspector = Rails::Application::RouteInspector.new
+ inspector.format(routes, ENV['CONTROLLER']).join "\n"
@pixeltrix Owner

Not sure there's much point in passing ENV['CONTROLLER'] here - it's used in the rake task to focus on a particular controller, e.g: rake routes CONTROLLER=products. Perhaps we could pass a url parameter instead, e.g:

# can't  use :controller here obviously
get '/rails/info/routes(/:filter)' => 'rails/info#routes'

class Rails::InfoController < ActionController::Base
  def routes
    @inspector = Rails::Application::RouteInspector.new
    @info = @inspector.format(_routes.routes, params[:filter]).join("\n")
  end
end

That way you don't need the RoutePresenter class.

A couple more points:

  1. Do you need the explicit render calls - does the default render not select the right templates?
  2. Do we need the explicit layout 'application' - does the layout not get selected correctly?

Not really bothered whether the explicit calls are there or not - I'm just wondering why you put them there.

@josevalim Owner
@schneems Collaborator

1) In my testing we needed to explicitly call layout or none will be rendered, not sure why.
2) Didn't try not explicitly calling render, when I take those lines out, it works fine...good catch.

I can kill the presenter, going with the cmd+f option. I would eventually like to pass it a url /users/5/whatever/3 and have it give me all the routes it matches since we can't Cmd+F for that, but for now i'm looking to get this out the door. I can experiment with filters/layouts in my free time on sextant, and just port over the most relevant/used features.

Unfortunately _routes is a different class than expected by the inspector, final version will now look like this:

  def routes
    inspector = Rails::Application::RouteInspector.new
    @info     = inspector.format(Rails.application.routes.routes).join("\n")
  end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@schneems
Collaborator

updated code to not use render and removed the presenter

@pixeltrix
Owner

Interesting about the layout - I'll have to check what's going on there. The _routes.routes should work but don't bother changing it - I'll merge it in as is.

@pixeltrix
Owner

Sorry, forgot one thing - it needs a CHANGELOG entry.

@josevalim
Owner

This is looking good! :clap:

schneems added some commits
@schneems schneems /rails/info/routes path shows routing information
Will show similar contents to the output of `$ rake routes` in the browser in development. This speeds the time required to generate routes, since the application is already initialized.
cb44e0f
@schneems schneems Rails::InfoController tests passing
This includes new tests for /rails/info/routes
c3e3102
@schneems
Collaborator

Switched over to _routes.routes to save a few characters. Added a change log entry, thanks for all the help guys. Hope you don't mind @pixeltrix, added you to the changelog.

@pixeltrix pixeltrix merged commit 8186754 into rails:master
@tenderlove

I don't see where the RoutePresenter is defined. Am I missing something?

Collaborator

Nope, we refactored it out, we need to remove this test, good catch. Want a PR?

please.

Collaborator

Submitted PR #6481, sorry about that.

@lance-io

Great job guys!

@vijaydev vijaydev referenced this pull request from a commit
@schneems schneems routes are viewable in browser (update guides)
From the Pull Request #6461
e636663
@theodorton theodorton referenced this pull request from a commit in theodorton/rails
@schneems schneems remove unused route reloading code
Since the environment is initialized each time rake is run, routes don't need to be re-loaded. rails#6461 (comment)
0460949
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on May 24, 2012
  1. @schneems

    /rails/info/routes path shows routing information

    schneems authored
    Will show similar contents to the output of `$ rake routes` in the browser in development. This speeds the time required to generate routes, since the application is already initialized.
  2. @schneems

    Rails::InfoController tests passing

    schneems authored
    This includes new tests for /rails/info/routes
This page is out of date. Refresh to see the latest.
View
2  railties/CHANGELOG.md
@@ -1,5 +1,7 @@
## Rails 4.0.0 (unreleased) ##
+* Add `/rails/info/routes` path, displays same information as `rake routes` *Richard Schneeman & Andrew White*
+
* Improved `rake routes` output for redirects *Łukasz Strzałkowski & Andrew White*
* Load all environments available in `config.paths["config/environments"]`. *Piotr Sarnacki*
View
2  railties/lib/rails/application/finisher.rb
@@ -23,6 +23,8 @@ module Finisher
if Rails.env.development?
app.routes.append do
get '/rails/info/properties' => "rails/info#properties"
+ get '/rails/info/routes' => "rails/info#routes"
+ get '/rails/info' => "rails/info#index"
end
end
end
View
2  railties/lib/rails/application/route_inspector.rb
@@ -51,7 +51,7 @@ def action
end
def internal?
- path =~ %r{/rails/info/properties|^#{Rails.application.config.assets.prefix}}
+ path =~ %r{/rails/info.*|^#{Rails.application.config.assets.prefix}}
end
def engine?
View
32 railties/lib/rails/info_controller.rb
@@ -1,15 +1,33 @@
+require 'rails/application/route_inspector'
+
class Rails::InfoController < ActionController::Base
+ self.view_paths = File.join(File.dirname(__FILE__), 'templates')
+ layout 'application'
+
+ before_filter :require_local!
+
+ def index
+ redirect_to '/rails/info/routes'
+ end
+
def properties
- if consider_all_requests_local? || request.local?
- render :inline => Rails::Info.to_html
- else
- render :text => '<p>For security purposes, this information is only available to local requests.</p>', :status => :forbidden
- end
+ @info = Rails::Info.to_html
+ end
+
+ def routes
+ inspector = Rails::Application::RouteInspector.new
+ @info = inspector.format(_routes.routes).join("\n")
end
protected
- def consider_all_requests_local?
- Rails.application.config.consider_all_requests_local
+ def require_local!
+ unless local_request?
+ render :text => '<p>For security purposes, this information is only available to local requests.</p>', :status => :forbidden
+ end
+ end
+
+ def local_request?
+ Rails.application.config.consider_all_requests_local || request.local?
end
end
View
32 railties/lib/rails/templates/layouts/application.html.erb
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8" />
+ <title>Routes</title>
+ <style>
+ body { background-color: #fff; color: #333; }
+
+ body, p, ol, ul, td {
+ font-family: helvetica, verdana, arial, sans-serif;
+ font-size: 13px;
+ line-height: 18px;
+ }
+
+ pre {
+ background-color: #eee;
+ padding: 10px;
+ font-size: 11px;
+ white-space: pre-wrap;
+ }
+
+ a { color: #000; }
+ a:visited { color: #666; }
+ a:hover { color: #fff; background-color:#000; }
+ </style>
+</head>
+<body>
+<h2>Your App: <%= link_to 'properties', '/rails/info/properties' %> | <%= link_to 'routes', '/rails/info/routes' %></h2>
+<%= yield %>
+
+</body>
+</html>
View
1  railties/lib/rails/templates/rails/info/properties.html.erb
@@ -0,0 +1 @@
+<%= @info.html_safe %>
View
9 railties/lib/rails/templates/rails/info/routes.html.erb
@@ -0,0 +1,9 @@
+<h2>
+ Routes
+</h2>
+
+<p>
+ Routes match in priority from top to bottom
+</p>
+
+<p><pre><%= @info %></pre></p>
View
9 railties/test/application/route_inspect_test.rb
@@ -164,5 +164,14 @@ def test_redirect
assert_equal " bar GET /bar(.:format) redirect(307, path: /foo/bar)", output[1]
assert_equal "foobar GET /foobar(.:format) redirect(301)", output[2]
end
+
+ def test_presenter
+ output = draw do
+ get "/foo" => redirect("/foo/bar"), :constraints => { :subdomain => "admin" }
+ get "/bar" => redirect(path: "/foo/bar", status: 307)
+ get "/foobar" => redirect{ "/foo/bar" }
+ end
+ assert_equal output.join("\n"), Rails::Application::RoutePresenter.display_routes(@set.routes)
+ end
end
end
View
12 railties/test/application/routing_test.rb
@@ -15,12 +15,24 @@ def teardown
teardown_app
end
+ test "rails/info/routes in development" do
+ app("development")
+ get "/rails/info/routes"
+ assert_equal 200, last_response.status
+ end
+
test "rails/info/properties in development" do
app("development")
get "/rails/info/properties"
assert_equal 200, last_response.status
end
+ test "rails/info/routes in production" do
+ app("production")
+ get "/rails/info/routes"
+ assert_equal 404, last_response.status
+ end
+
test "rails/info/properties in production" do
app("production")
get "/rails/info/properties"
View
17 railties/test/rails_info_controller_test.rb
@@ -12,29 +12,28 @@ class InfoControllerTest < ActionController::TestCase
def setup
Rails.application.routes.draw do
get '/rails/info/properties' => "rails/info#properties"
+ get '/rails/info/routes' => "rails/info#routes"
end
- @request.stubs(:local? => true)
- @controller.stubs(:consider_all_requests_local? => false)
+ @controller.stubs(:local_request? => true)
@routes = Rails.application.routes
Rails::InfoController.send(:include, @routes.url_helpers)
end
test "info controller does not allow remote requests" do
- @request.stubs(:local? => false)
+ @controller.stubs(:local_request? => false)
get :properties
assert_response :forbidden
end
test "info controller renders an error message when request was forbidden" do
- @request.stubs(:local? => false)
+ @controller.stubs(:local_request? => false)
get :properties
assert_select 'p'
end
test "info controller allows requests when all requests are considered local" do
- @request.stubs(:local? => false)
- @controller.stubs(:consider_all_requests_local? => true)
+ @controller.stubs(:local_request? => true)
get :properties
assert_response :success
end
@@ -48,4 +47,10 @@ def setup
get :properties
assert_select 'table'
end
+
+ test "info controller renders with routes" do
+ get :routes
+ assert_select 'pre'
+ end
+
end
Something went wrong with that request. Please try again.