How can I find out the current route in Rails?
Asked Answered
M

14

249

I need to know the current route in a filter in Rails. How can I find out what it is?

I'm doing REST resources, and see no named routes.

Metabolism answered 30/7, 2009 at 0:50 Comment(2)
What are you trying to accomplish with this? When you say "route" do you mean "URI"?Anthropoid
any thoughts on how to get it in middleware.Droplet
C
218

To find out URI:

current_uri = request.env['PATH_INFO']
# If you are browsing http://example.com/my/test/path, 
# then above line will yield current_uri as "/my/test/path"

To find out the route i.e. controller, action and params:

path = ActionController::Routing::Routes.recognize_path "/your/path/here/"

# ...or newer Rails versions:
#
path = Rails.application.routes.recognize_path('/your/path/here')

controller = path[:controller]
action = path[:action]
# You will most certainly know that params are available in 'params' hash
Crazy answered 30/7, 2009 at 10:48 Comment(6)
Would you happen to know if this is the same/right way to do it in Rails 3? I'm sure it's still accessible, but I just want to be sure that I'm adhering to the latest conventions.Bypath
The current controller and action are always available in params[:controller] and params[:action]. However, outside of it, if you want to recognize the route, this API is not available anymore. It has now shifted to ActionDispatch::Routing and I haven't tried out the recognize_path on it yet.Crazy
It’s better to use request.path for finding the current path.Rior
You could also call request.env['ORIGINAL_FULLPATH'] to include the possible parameters in the path, see my answer below.Acerbic
current_uri = request.env['PATH_INFO'] doesn't work if trailing_slash is set in routesRadiograph
@Metabolism The same approach does not work here, any thoughts?Droplet
S
339

If you are trying to special case something in a view, you can use current_page? as in:

<% if current_page?(:controller => 'users', :action => 'index') %>

...or an action and id...

<% if current_page?(:controller => 'users', :action => 'show', :id => 1) %>

...or a named route...

<% if current_page?(users_path) %>

...and

<% if current_page?(user_path(1)) %>

Because current_page? requires both a controller and action, when I care about just the controller I make a current_controller? method in ApplicationController:

  def current_controller?(names)
    names.include?(current_controller)
  end

And use it like this:

<% if current_controller?('users') %>

...which also works with multiple controller names...

<% if current_controller?(['users', 'comments']) %>
Silicosis answered 4/12, 2010 at 16:38 Comment(11)
Note that you can also use current_page? with named routes: current_page?(users_path)Flytrap
Nice tothemario. I didn't know that. I'm modifying the answer.Silicosis
it returns true whatever address is "/users", "/users/", "/users?smth=sdfasf".... Sometimes not so good thing in practiceRadiograph
controller_name and action_name are good for use in helpers and views for this sort of thing too.Vaporous
Building on @Gediminas and @MattConnolly comments... current_page? needs at least the controller and the action. If you need just the controller, you can use controller_name == 'users'. I make a current_controller? helper that does that check and put it in ApplicationController.Silicosis
In a view you can also just do <% if params[:action] == 'show' %> so you don't need the controllerSlater
How do I apply this if I have a subdomain?Salina
I implemented this current_page logic in my application layout, and it ended up breaking the devise new confirmation page. I had this code: if current_page?(:controller => 'pages', :action => 'about'), and the users/confirmation/new page fails with this error: No route matches {:action=>"about", :controller=>"devise/pages"}. I fixed with if request.path == "/pages/about" from an answer below.Aileenailene
In Rails 6 (and probably as early as Rails 4 or 5), you can simply provide an active record object: current_page?(@user) or collection current_page?(@users). Rails uses polymorphic_path under the hood to generate the path from the given active record object. Pretty neat!Bankhead
It's true! It goes back to 1.0.0 actually. This works because ActionView will interpret @user as the path \user\:id. If the person is on the edit action users#edit it will return false, however, because the actual current page is \user\:id\edit. So it will work depending on what you are trying to do.Silicosis
For best practice, the current_controller? method would be better defined in a helper (perhaps ApplicationHelper) instead of in a controller.Ruvolo
C
218

To find out URI:

current_uri = request.env['PATH_INFO']
# If you are browsing http://example.com/my/test/path, 
# then above line will yield current_uri as "/my/test/path"

To find out the route i.e. controller, action and params:

path = ActionController::Routing::Routes.recognize_path "/your/path/here/"

# ...or newer Rails versions:
#
path = Rails.application.routes.recognize_path('/your/path/here')

controller = path[:controller]
action = path[:action]
# You will most certainly know that params are available in 'params' hash
Crazy answered 30/7, 2009 at 10:48 Comment(6)
Would you happen to know if this is the same/right way to do it in Rails 3? I'm sure it's still accessible, but I just want to be sure that I'm adhering to the latest conventions.Bypath
The current controller and action are always available in params[:controller] and params[:action]. However, outside of it, if you want to recognize the route, this API is not available anymore. It has now shifted to ActionDispatch::Routing and I haven't tried out the recognize_path on it yet.Crazy
It’s better to use request.path for finding the current path.Rior
You could also call request.env['ORIGINAL_FULLPATH'] to include the possible parameters in the path, see my answer below.Acerbic
current_uri = request.env['PATH_INFO'] doesn't work if trailing_slash is set in routesRadiograph
@Metabolism The same approach does not work here, any thoughts?Droplet
S
179

Simplest solution I can come up with in 2015 (verified using Rails 4, but should also work using Rails 3)

request.url
# => "http://localhost:3000/lists/7/items"
request.path
# => "/lists/7/items"
Synergetic answered 15/3, 2015 at 0:38 Comment(2)
And if you want the id in the view: <%= request.path_parameters[:id] %>Slater
This is awesome! Use this in a partial form to redirect to the current page with new params. <form action="<%= request.path %>">Lepto
L
21

You can do this

Rails.application.routes.recognize_path "/your/path"

It works for me in rails 3.1.0.rc4

Lennon answered 13/7, 2011 at 14:54 Comment(1)
This returns a hash which is the params hash. Any way to actually get the route object? With the name and then other attributes?Soldiery
I
11

In rails 3 you can access the Rack::Mount::RouteSet object via the Rails.application.routes object, then call recognize on it directly

route, match, params = Rails.application.routes.set.recognize(controller.request)

that gets the first (best) match, the following block form loops over the matching routes:

Rails.application.routes.set.recognize(controller.request) do |r, m, p|
  ... do something here ...
end

once you have the route, you can get the route name via route.name. If you need to get the route name for a particular URL, not the current request path, then you'll need to mock up a fake request object to pass down to rack, check out ActionController::Routing::Routes.recognize_path to see how they're doing it.

Improve answered 21/1, 2011 at 19:23 Comment(1)
Error: undefined method 'recognize' for #<Journey::Routes:0x007f893dcfa648>Cott
D
9

Based on @AmNaN suggestion (more details):

class ApplicationController < ActionController::Base

 def current_controller?(names)
  names.include?(params[:controller]) unless params[:controller].blank? || false
 end

 helper_method :current_controller?

end

Now you can call it e.g. in a navigation layout for marking list items as active:

<ul class="nav nav-tabs">
  <li role="presentation" class="<%= current_controller?('items') ? 'active' : '' %>">
    <%= link_to user_items_path(current_user) do %>
      <i class="fa fa-cloud-upload"></i>
    <% end %>
  </li>
  <li role="presentation" class="<%= current_controller?('users') ? 'active' : '' %>">
    <%= link_to users_path do %>
      <i class="fa fa-newspaper-o"></i>
    <% end %>
  </li>
  <li role="presentation" class="<%= current_controller?('alerts') ? 'active' : '' %>">
    <%= link_to alerts_path do %>
      <i class="fa fa-bell-o"></i>
    <% end %>
  </li>
</ul>

For the users and alerts routes, current_page? would be enough:

 current_page?(users_path)
 current_page?(alerts_path)

But with nested routes and request for all actions of a controller (comparable with items), current_controller? was the better method for me:

 resources :users do 
  resources :items
 end

The first menu entry is that way active for the following routes:

   /users/x/items        #index
   /users/x/items/x      #show
   /users/x/items/new    #new
   /users/x/items/x/edit #edit
Diehard answered 29/12, 2014 at 20:57 Comment(0)
S
7

Or, more elegantly: request.path_info

Source:
Request Rack Documentation

Scrogan answered 5/2, 2015 at 22:8 Comment(0)
A
6

Should you also need the parameters:

current_fullpath = request.env['ORIGINAL_FULLPATH']
# If you are browsing http://example.com/my/test/path?param_n=N 
# then current_fullpath will point to "/my/test/path?param_n=N"

And remember you can always call <%= debug request.env %> in a view to see all the available options.

Acerbic answered 5/10, 2012 at 11:47 Comment(0)
H
4

I'll assume you mean the URI:

class BankController < ActionController::Base
  before_filter :pre_process 

  def index
    # do something
  end

  private
    def pre_process
      logger.debug("The URL" + request.url)
    end
end

As per your comment below, if you need the name of the controller, you can simply do this:

  private
    def pre_process
      self.controller_name        #  Will return "order"
      self.controller_class_name  # Will return "OrderController"
    end
Hassler answered 30/7, 2009 at 1:27 Comment(2)
yes I did that, but I hoped in a better way. What I need is to know which controller has been called, but I have pretty complicated nested resources.. request.path_parameters('controller') doesn't seem to work properly to me.Metabolism
No need for self. in self.controller_name and self.controller_class_nameSynergetic
J
4

request.url

request.path #to get path except the base url

Jarredjarrell answered 11/5, 2016 at 13:21 Comment(0)
B
2

You can see all routes via rake:routes (this might help you).

Benham answered 30/7, 2009 at 2:55 Comment(1)
I prefer to open a new tab with an invalid path, and see all the path/routes from the browser, since they're prettier that way. But I don't think this helps get the current route.Dubitable
B
1

You can do this:

def active_action?(controller)
   'active' if controller.remove('/') == controller_name
end

Now, you can use like this:

<%= link_to users_path, class: "some-class #{active_action? users_path}" %>
Bodnar answered 2/10, 2018 at 18:14 Comment(0)
C
1

I find that the the approved answer, request.env['PATH_INFO'], works for getting the base URL, but this does not always contain the full path if you have nested routes. You can use request.env['HTTP_REFERER'] to get the full path and then see if it matches a given route:

request.env['HTTP_REFERER'].match?(my_cool_path)
Czardom answered 26/1, 2021 at 22:14 Comment(0)
S
0

You can do request.env['REQUEST_URI'] to see the full requested URI.. it will output something like below

http://localhost:3000/client/1/users/1?name=test
Sporty answered 9/8, 2017 at 23:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.