Rails 4 Upgrade - ActionController::UrlGenerationError - No route matches - ruby-on-rails

I am trying to port my application from Rails 3.2.x to Rails 4.0.4. All the gems have been made compatible and I am in the phase of fixing failing tests.
I have this weird test failure.
My routes.rb
resources :my_reports, only: [:index] do
collection do
get "/report/:filename", to: :show, prefix: "pri/excl/rep", as: :show
end
end
My spec which has been passing in Rails 3.2.x and now failing after update to 4.0.4
describe MyReportsController do
describe "#show" do
def make_request
get :show, prefix: 'some/place', filename: 'foo', format: 'doc'
end
it "makes a simple request" do
make_request
end
end
end
I am getting the following error
Failure/Error: get :show, prefix: 'some/place', filename: 'foo', format: 'doc'
ActionController::UrlGenerationError:
No route matches {:action=>"show", :controller=>"my_reports",
:filename=>"foo", :format=>"doc", :prefix=>"some/place"}
I am stuck at this point, hints are welcome. I am using rspec and rspec-rails versions 2.14.1.

Passing a dummy :id in the test fixed the issue for me although I would not like it, tests pass.
get :show, id: "", prefix: 'some/place', filename: 'foo', format: 'doc'
Refer to state of rails releases here.

You're describing the show method but your route is only available for the index one. Maybe it's a beginning of solution.

Related

Rails routes testing

I am new to testing and I have a question.
This code tests if that route is correct, ok?
test "root should route to home#index" do
assert_routing "/", {controller: "home", action: "index"}
end
How can I test the opposite? I have
resources :sessions, :only=>[:new, :create, :destroy]
In my routes. How would I test that you can't enter sessions#edit?
Could it be that I should not test that?
EDIT: I forgot to mention it, I'm using the default tools.
You could try this, it will fail unless the test assert_generates raises an "UrlGenerationError" => unable to generate the url for sessions#edit
test "route should not exist" do
begin
assert_generates "sessions/edit", controller: :sessions, action: :edit
flunk "Route to should not exist"
rescue ActionController::UrlGenerationError
end
end
If you're using RSpec you could do
it "does not route to sessions/edit" do
expect(:get => "/sessions/edit").not_to be_routable
end
See https://relishapp.com/rspec/rspec-rails/docs/routing-specs/be-routable-matcher for more information on writing routing specs

Rails: how to test and access custom routing

so far in routes.rb
match 'campaigns_mobile_application', to: 'campaigns#update_mobile_store_application', via: [:post, :get]
in spec_helper.rb
config.include Rails.application.routes.url_helpers
in controller_spec.rb
get campaigns_mobile_application_path format: :json # and here I have error
ok, I have error:
ActionController::RoutingError No route matches {:controller=>"campaigns", :action=>"/api/campaigns_mobile_application.json"}
change routes.rb now:
resources :campaigns do
match 'mobile_application', to: 'campaigns#update_mobile_store_application', via: [:post, :get]
end
and also spec:
get campaign_mobile_application_path campaign_id: #campaign.id, format: :json
and again I catch error:
ActionController::RoutingError:
No route matches {:controller=>"campaigns", :action=>"/api/campaigns/6775/mobile_application.json"}
How to fix this?
UPD:
I try different magic with on: :member, on: :collection, as: :name and other stuff.
Seems that I completely doesn't understand routing.
routes.rb
resources :campaigns do
match :mobile_applications, to: 'campaigns#update_mobile_store_applications',
via: [:post, :get], on: :member, as: :mobile_applications
end
**rake routes **
mobile_applications_campaign POST|GET /api/campaigns/:id/mobile_applications(.:format) campaigns#update_mobile_store_applications
controller.rb
def update_mobile_store_applications
render: json: { }, status: :ok
end
spec.rb
get mobile_applications_campaign_path campaign_id: #campaign.id, format: :json
generate error:
Failure/Error: get mobile_applications_campaign_path campaign_id: #campaign.id, format: :json
ActionController::RoutingError:
No route matches {:action=>"update_mobile_store_applications", :controller=>"campaigns", :campaign_id=>8059, :format=>:json}
change request to this one (rename parameter):
get mobile_applications_campaign_path id: #campaign.id, format: :json
still generate error: ( different error )
Failure/Error: get mobile_applications_campaign_path id: #campaign.id, format: :json
ActionController::RoutingError:
No route matches {:controller=>"campaigns", :action=>"/api/campaigns/8108/mobile_applications.json"}
UPD2
This code works well on app but not in testing.
UPD3
This code works well on testing too now! Yeah!
get :update_mobile_store_applications, id: #campaign.id, format: :json
get :mobile_applications_campaign_path, id: #campaign.id, format: :json
The format was incorrect look here: https://github.com/everydayrails/rails-4-1-rspec-3-0/blob/master/spec/controllers/contacts_controller_spec.rb
This code is part of a Everyday Rails Testing book, a very good book for learn testing with rspec on Rails

How to test custom routes in controller with rspec

I have defined a custom route in
routes.rb
get "packages/city/:location_id", to: "packages#index"
In controller_spec.rb,
get :index
gives this error,
ActionController::UrlGenerationError:
No route matches {:action=>"index", :controller=>"packages"}
How to explicitly specify the custom routes in controller specs?
Perhaps it helps if you declare your route like this?
get "packages/city/:location_id" => "packages#index"
Remember to provide a location_id param in specs, e.g. get :index, location_id: 1.
2017
I tried the solutions above but they did not work. I got:
ArgumentError:
unknown keyword: location_id
It seems that RSpec now requires a params parameter. The corresponding call would look like this:
get(:index, params: { location_id: 123 })
it's because you are not passing location_id
the route is defined to match:
/packages/city/:location_id
so in order to comply with it you need to do something like
get :index, location_id: 1234
Had the same issue with Controller spec:
# rake routes | grep media_order
teacher_work_media_orders PATCH /teacher/works/:work_id/media_orders(.:format) teacher/media_orders#update
when I did:
# spec/controller/teacher/media_orders_controller
patch :update data: {}
I got
Failure/Error: patch :update
ActionController::UrlGenerationError:
No route matches {:action=>"update", :controller=>"teacher/media_orders"}
but when I did
patch :update, work_id: 1234, data: {}
that worked
2019
Was tackling this same error on my controller specs. Tried accepted and follow up solutions, but they also did not work, either led to no method error or persisted the no route match error.
Directly defining the route like in the accepted solution also did not satisfy the errors.
After much searching and some keyboard smashing tests pass.
Things to note
controller is for polymorphic resource
routes are nested within the resources :location, only[:index, :show] do ... end
this is API routes, so JSON only
Solution
let(:location) do
create(:location)
end
shared_examples("a user who can't manage locations") do
describe 'GET #index' do
it 'denies access' do
get :index, params:{location_id: location.locationable.id, format: :json}
expect(response).to have_http_status :unauthorized
end
end
end
So in the end it was a combination of both solutions, but had to put them in the params hash or else it would throw name/no method or route errors
Conclusion
references to the association must be in the params hash
even if controller responds_to :json, it will throw errors no route errors
must include a data hash in your request or no route match errors will appear
Hope this helps,
Cheers!

RSpec 3.1 upgrade: namespaced routes not recognized any more

After an upgrade from Rails 3.0 to 3.2.21 and RSpec from 2.14 to 3.1, my API routes (namespaced, see below) aren't working any more. Specifically, they appear in rake routes and work in the browser in development mode, but they cause "Route not found" exceptions in tests and I cannot get them recognized in the console (but this might be my ignorance... any help appreciated).
Other (non-namespaced) routes work fine.
Here are the route definitions:
namespace :api, path: '', defaults: { format: :json }, constraints: { format: :json, subdomain: 'api' } do
namespace :v1 do
resources :foos, only: [:index] do
post :bar, on: :collection
end
end
end
match '*path' => 'application#route_not_found' # default 404 route
Here is the rake routes output:
bar_api_v1_foo_index POST /v1/foo/bar(.:format) api/v1/foo#bar {:format=>:json, :subdomain=>"api"}
api_v1_foo DELETE /v1/foo/:id(.:format) api/v1/foo#destroy {:format=>:json, :subdomain=>"api"}
Here is my spec (in spec/integration/api_v1_foo_controller_spec.rb):
require "spec_helper"
describe Api::V1::FooController do
before do
host! "api.#{host}" # set subdomain, see http://elia.schito.me/2011/09/15/set-subdomain-in-rails-3-request-specs/
end
describe "POST" do
it "should bar" do
post "/v1/foo/bar"
end
end
end
Here is the spec output:
Failures:
1) Api::V1::FooController POST should bar
Failure/Error: post "/v1/foo/bar"
ActionController::RoutingError:
No route matches [POST] "/v1/foo/bar"
# /opt/local/lib/ruby2.1/gems/2.1.0/gems/actionpack-3.2.21/lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call'
# /opt/local/lib/ruby2.1/gems/2.1.0/gems/actionpack-3.2.21/lib/action_dispatch/middleware/show_exceptions.rb:56:in `call'
My feeble attempts at getting the routes to work in the console also fail, but for all Rails versions. It's probably the syntax (how do you use this?).
Rails.application.routes.recognize_path '/v1/foo/bar', method: :post, subdomain: 'api', format: :json
=> {:controller=>"application", :action=>"route_not_found", :path=>"v1/foo/bar"}
Why does the test above fail after the upgrade to Rails 3.2 and Rspec 3.1?
Update
This is probably an effect of a RoR bug: https://github.com/rails/rails/issues/8679
If I remove subdomain: 'api' inside the constraints block of the routes definition, all of Rails 3.2.21, 4.1.9 and 4-2-stable will accept the routes and work. If I force the spec to be a request spec and change the host! "api.#{host}" to host! "api.example.com", the routing also works.
Is this intentional? Is there an alternate way of restricting a route to a specific subdomain?

All get/put calls error w/"no route matches" in rspec tests; though they work fine in app

Routes that work fine in my application fail on any get/put call in rspec testing with 'No route matches'. What am I doing wrong here?
Here's a simple example, from contracts_controller_spec.rb:
it 'should redirect to edit on show' do
get :show
response.should be_success
response.should render_template(:edit)
end
The above fails with the following:
ContractsController api calls should redirect to edit on show
Failure/Error: get :show
ActionController::RoutingError:
No route matches {:controller=>"contracts", :action=>"show"}
the show method in contracts_controller.rb:
def show
Rails.logger.debug("getting contract info....")
get_contract_info
Rails.logger.debug("...got contract info.")
render :action => :edit
end
routes.rb content:
resource :contract, :only=>[:show, :edit, :update], :protocol =>ROUTES_PROTOCOL do
member do
get :print
end
end
rake routes output:
print_contract GET /contract/print(.:format) contracts#print {:protocol=>"http"}
edit_contract GET /contract/edit(.:format) contracts#edit {:protocol=>"http"}
contract GET /contract(.:format) contracts#show {:protocol=>"http"}
PUT /contract(.:format) contracts#update {:protocol=>"http"}
using rspec-rails 2.14.0
This app was recently upgraded from Rails 2.3 to 3.2, which has otherwise been successful
note the non-standard show/edit routes: no id is required, and forcing an id still results in No route matches {:controller=>"contracts", :id=>"1", :action=>"show"}
:protocol is bit weird, try to remove ??

Resources