So I have a snazzy custom route for login

# routes.rb
map.login '/login', :controller => 'sessions', :action => 'new'

Visit and you're there. As is custom with failed login, however, we'll do the following in our action. Note what happens on failed login.

 # sessions_controller.rb

 def create
   self.current_user = User.authenticate(params[:email], params[:password])
   if logged_in?
     # some work and redirect the user
   else[:warning] = "The email and/or password you entered is invalid."
     render :action => 'new'

This is very typical. Simply render the new action and prompt for login again. Unfortunately you also get with it an ugly URL: Ick! Is it possible to get rendering to respect the original URL?

No correct solution


Your problem is this: the user first visits /login and fills in the form. When they submit the form, they POST to /sessions, which is why the browser URL changes. To get around this you can do two things:

As Michael mentioned, you can redirect back to the :new action, changing the else to:

   flash[:warning] = "The email and/or password you entered is invalid."
   redirect_to login_path

Note that you'll need to change the flash so the message is available in the next request (following the redirect).

The second method is slightly hackier, but maybe worth mentioning. By using conditions on your routes, you can map both the login form (which is a GET) and the form submit (which is a POST) to the same path. Something like:

map.login '/login',
  :controller => 'sessions', :action => 'new', 
  :conditions => {:method => :get}

map.login_submit '/login',
  :controller => 'sessions', :action => 'create', 
  :conditions => {:method => :post}

Then if your form action is login submit path, things should work as you expect.

Change render :action => 'new' to redirect_to login_path

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow