Torsten Bühl
Software Engineer & Founder

Hi, I'm Torsten. I am the founder of Foodlane, Company Signal, and Exceptiontrap (acquired by Scout APM). I strive to build simple and beautiful software products that people love to use. Learn more about them here

Rails 4 upgrade gotcha #1 (routes definition)

Torsten Bühl

When I upgraded from Rails 3 to 4, I ran into some problems which I will share here.

If you use Sorcery or Authlogic for authorization, you create your login and logout routes by yourself. I found this code in my routes.rb file, where the /login path is used for GET and POST requests and can be refered to as login_path.

# Rails 3
match '/login' => 'sessions#new', as: :login, via: 'get'
match '/login' => 'sessions#create', as: :login, via: 'post'

While this works well with Rails 3, you get the following error with Rails 4:

/gems/actionpack-4.0.0/lib/action_dispatch/routing/route_set.rb:409:in `add_route': Invalid route name, already in use: 'login'  (ArgumentError)
You may have defined two routes with the same name using the `:as` option, or you may be overriding a route already defined by a resource with the same naming. For the latter, you can restrict the routes created with `resources` as explained here: ...

How to fix this? Just use get and post instead of match to describe the routes and remove the as option.

# Rails 4
get 'login' => 'sessions#new'
post 'login' => 'sessions#create'

This looks shorter and nicer, plus both routes are still available as login_path.

So far so good, but how does this work with routes containing variables? Like here:

# Rails 3
match '/signup/:plan' => 'accounts#create', as: :signup, via: 'post'
match '/signup/:plan' => 'accounts#new', as: :signup, via: 'get'

The solution: just use get and post like above. To make it available as a named route, you have to set the as option for the first route. The second will be automatically available under the same name.

# Rails 4
get 'signup/:plan' => 'accounts#new', as: :signup
post 'signup/:plan' => 'accounts#create'