Route definitions matter
Note: this post was migrated from my old Tumblr-backed blog
Since this past friday, I’ve been dedicating the majority of my time to getting our RSpec tests to pass on our API orders controller. Being that I was tasked with adding some features to this endpoint, I wanted to make sure the existing tests were passing before writing new ones. This would give me a good baseline to begin work and ensure that my code functions as required.
Now, this particular component of our system has gone through a lot of refactoring in the last 6 months and the tests haven’t been kept up, so there were a bunch of failures that were just the result of out of date tests and were very easy to get working again. Then came this doozy.
First some background on the system:
When creating the order in the system, we have 2 endpoints that actually point to the same create
action in our orders controller. This is defined in our routes.rb
file as follows:
resources :orders, :only => [:index, :show, :create, :update] do
post :another_action, :on => :collection
# the problem action is right here:
post :action_in_question, :on => :collection, :action => :create
member do
post :a
post :b
post :c
end
end
With this, one is able to post to /orders or /orders/action_in_question and both will hit our create
action, but behave slightly differently.
We do this with code like the following:
if request.path.include?('action_in_question')
# special treatment
end
The problem arose when we would call post :create, post_params
on the orders controller. The URI exposed to the controller always included action_in_question
.
When running rake routes
I could see that the POST /orders/action_in_question
route was always listed before the POST /orders
action as well, so I focused my energy on solving this.
The solution was to ensure that this action_in_question
action would be lower down in the list so it wouldn’t be automatically generated by RSpect. This was accomplished by changing the above route to look like:
resources :orders, :only => [:index, :show, :create, :update] do
post :another_action, :on => :collection
# the problem action is right here:
post :action_in_question, :on => :collection, :action => :create
member do
post :a
post :b
post :c
end
end
# re-open this nested route and declare action_in_question here
resources :orders, :only => [:index, :show, :create, :update] do
post :action_in_question, :on => :collection, :action => :create
end
That successfully solved our issue and the tests now generate the correct URI.