1

I have been programming in Ruby on Rails for a while now, but never really dug deep into routing until recently. After reading a fair amount of documentation and googling, I haven't been able to answer this question.

How do you change a URL after a route is matched? To better explain this, let me set a scenario I'm trying to solve. The root of my website while testing is localhost:3000. My login page is localhost:3000/login. Once logged in though, I want the URL to read localhost:3000 again with no extension. The actual page name is dashboard and my route is as follows currently.

get 'dashboard' => 'user#dashboard'

This only matches when the URL is localhost:3000/dashboard, but I wan't to have cleaner URL like a lot of sites have. How is this achieved with Ruby On Rails? I want to avoid a javascript solutions or anything that is a workaround.

Any help or tips is greatly appreciated. Many thanks in advance.

ChristopherW
  • 993
  • 1
  • 12
  • 25

2 Answers2

1

I've provided the solution below, but I agree with max that your wanting to make a RESTful URL less meaningful is backwards. You should strive to alias a URL to make it more meaningful (e.g. from site.com/posts/34239482069472/ to site.com/posts/my-post-title).

The URL that appears in the address bar is an instruction to an app. When a user puts "site.com/dashboard" into the address bar, they're instructing the app to make an HTTP request get 'dashboard'. The Controller#action is a set of instructions the app executes when it receives that request. If you're following Rails naming convention then Users#dashboard will retrieve data and then by default render the view template at views/users/dashboard.html.erb. Understand this: you're not changing the URL for a given view, you're changing which view template is rendered by the Controller#action that is set for that url.

This means the Controller#action for your root_url (i.e. your root to: 'controller#action' in config/routes.rb) should render one view template if user is logged in and a different view template if a user is not logged in. Assuming root to: welcome#index, your controller action would look something like this:

app/controllers/welcome_controller.rb

def index
  # db queries, logic, set @variables

  if session[:user_id]
    render "users/dashboard" # app/views/users/dashboard.html.erb
  else
    render "index" # app/views/welcome/index.html.erb
  end
end

Note that if the view template you want to render corresponds to the controller, e.g. users_controller.rb action is rendering a view in views/users, then you only need to give the view name, otherwise you need to give a path (relative to app/views).

femmestem
  • 591
  • 2
  • 9
  • That is exactly what I was looking for thanks! It seems I'm going to have to think a bit harder about how I want to design the URL's. I completely agree that URL's should be as natural as possible, so I don't plan expose any id's through the URL at any time. I'm sure the more I play with it, the more I'll see what works best given my project. – ChristopherW Jul 06 '15 at 00:08
0

Why? /dashboard is a proper RESTful definition of a resource. In REST a route should have the same response independent of state. So having a radically different root page for a logged in user violates REST.

Also your users may want to access the index page as well the dashboard and you would be denying them that possibility.

These kind of URL micro-optimizations do not warrant hacking a bunch of state into your routes definitions.

max
  • 96,212
  • 14
  • 104
  • 165
  • The exception to the "same response independent of state" rule is of course access control. – max Jul 05 '15 at 04:23
  • What I'm aiming for is something similar to Github and Facebook in that when the user logs in, they see a summary page of activities on the website and their projects. Both of them have no URL extension and I think it's a really nice clean look. – ChristopherW Jul 05 '15 at 04:24