Software Developer and Founder Torsten Bühl

I am the founder of Company Signal, Exceptiontrap and Positron – SaaS products with a focus on simple usage and a beautiful & clean user-interface. Learn more about them here. You can also find some articles about software development (especially Ruby related) below.


Rails 4 upgrade gotcha #1 (routes definition)

22 Oct 2013

When I upgraded my Rails 3 applications to version 4, I ran into some problems which I want to 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.

# works in 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.

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:

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

The solution is 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.

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