227
votes

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.

14
What are you trying to accomplish with this? When you say "route" do you mean "URI"?jdl
any thoughts on how to get it in middleware.Saurabh

14 Answers

205
votes

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
314
votes

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']) %>
160
votes

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"
20
votes

You can do this

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

It works for me in rails 3.1.0.rc4

11
votes

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.

9
votes

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
6
votes

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.

6
votes

Or, more elegantly: request.path_info

Source:
Request Rack Documentation

4
votes

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
4
votes

request.url

request.path #to get path except the base url

2
votes

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

1
votes

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}" %>
1
votes

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)
0
votes

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