Rails 4 testing nested resources with multiple URL params - ruby-on-rails

I have been at this for a few hours, still can't figure it out. I have 2 tests on 2 actions on a nested resources controller. requests is the parent resources route, and response is the nested resources route.
These 2 tests give me a no route matches error. Does not make sense. In the first test, it tries to run the update action instead of the edit. Here are my tests:
test "should get edit" do
assert_routing edit_request_response_path(#myresponse.request_id, #myresponse), { :controller => "responses", :action => "edit", :request_id => #myresponse.request_id.to_s, :id => #myresponse.id.to_s }
get :edit, params: { id: #myresponse, request_id: #myresponse.request_id }
assert_response :success
end
test "should update response" do
post :update, :request_id => #myresponse.request_id, response: { body: #myresponse.body, request_id: #myresponse.request_id, status: #myresponse.status, subject: #myresponse.subject, user_id: #myresponse.user_id }
assert_redirected_to response_path(assigns(:response))
end
Here are the errors:
3) Error:
ResponsesControllerTest#test_should_get_edit:
ActionController::UrlGenerationError: No route matches {:action=>"edit", :controller=>"responses", :params=>{:id=>"980190962", :request_id=>"999788447"}}
test/controllers/responses_controller_test.rb:43:in `block in <class:ResponsesControllerTest>'
4) Error:
ResponsesControllerTest#test_should_update_response:
ActionController::UrlGenerationError: No route matches {:action=>"update", :controller=>"responses", :request_id=>"999788447", :response=>{:body=>"This is the body", :request_id=>"999788447", :status=>"draft", :subject=>"This is the subject", :user_id=>"175178709"}}
test/controllers/responses_controller_test.rb:48:in `block in <class:ResponsesControllerTest>'

In this case you might want to use shallow nesting since there is no reason to go through request if you can get to a response by /response/:id.
resources :requests, shallow: true do
resources :response
end
http://guides.rubyonrails.org/routing.html#nested-resources
test "should get edit" do
assert_routing edit_response_path(#myresponse), { :controller => "responses", :action => "edit", :id => #myresponse.id.to_s }
get :edit, params: { id: #myresponse, request_id: #myresponse.request_id }
assert_response :success
end
However naming your business logic objects Request and Response is a big misstake. These are already key concepts in Rails which correspond to the request from the client and the response sent to the client by rails.
You will end up confusing yourself and any poor sucker that has to work on the project. Plus you will end up masking the request and response methods that are pretty important parts of the ActionController API.
Use some other synonym instead.

Related

Use Patch with rspec tests

I am trying to test patch for devise user info using Rspec, the update url looks like this # PATCH/PUT /api/users/1 but I am getting this error for all the following cases
Error ArgumentError:
wrong number of arguments (given 2, expected 1)
Cases I tried
patch :update, {'id'=> #api_user['user']['id'], 'user' => attributes_for(:normal_user)}
patch :update, 'id'=> #api_user['user']['id'], 'user' => attributes_for(:normal_user)
patch :update, 'id'=> #api_user['user']['id'], :params => {'user' => attributes_for(:normal_user)}
And I tried this
patch :update, :params => {'user' => create(:normal_user)}. # this one has the id within
but gives this error
No route matches {:action=>"update", :controller=>"api/users", :user=>#<User id: 227794695, email: "test11#example.com", created_at: "2020-05-03 08:51:55", updated_at: "2020-05-03 08:51:55", is_admin: nil, first_name: "test", last_name: "test">} which make sence, the url should be update/id
you should not put "update" after patch, since
patch it self will automatically will route to update to user controller
this is the reason error message informed you given 2, expected 1 arguments
here is sample for your reference from update
require 'rails_helper'
RSpec.describe 'User request', type: :request do
it 'should update user email' do
patch "/api/users/#{#api_user['user']['id']}",
params: {
user: {
email: 'new_email_address#gmail.com'
}
},
as: :json
expect(response).to have_http_status(:success)
end
end
here is sample of /config/routes.rb for your reference to update users
Rails.application.routes.draw do
namespace :api, defaults: { format: :json } do
resources :users, only: [:create, :update, :destroy]
end
end

"No route matches" error in rspec, but route shows up in rake routes

Here is my route from routes.rb:
resources :books, :except => [:new, :edit] do
post "pull" => "books#update", :data => { "pull" => true }
rake routes shows things as expected
pull_api_v1_book POST /api/v1/books/:id/pull(.:format)
api/v1/books#update {:format=>:json, :data=>{"pull"=>true}}
Running a dev server, the route works as expected:
curl -X POST http://localhost:3000/api/v1/books/3/pull?auth_token=1234567890
My spec in in books_controller_spec.rb:
describe "pull api" do
it "should not fail" do
post :pull, params: { :id => 12 }
end
end
But the output of the spec:
Failure/Error: post :pull, params: { :id => 12 }
ActionController::UrlGenerationError:
No route matches {:action=>"pull", :controller=>"api/v1/books", :id=>12}
Why can't rspec find the route?
Controller tests in rails don't actually invoke the routing, it's only syntactic sugar for calling the controller action. Your spec should call:
post :update, params: { :id => 12 }
If you actually want to test the route you should use a request spec.

Rails[RSpec]: put :update, no route matches :id => nil

Very strange error. I am writing RSpec tests for a subgroup controller, which is in a many-to-one relationship with group. group accepts nested attributes for subgroup. I used scaffolding, and I've used the tests provided (edited to test). These tests were all working before I started testing for Devise. Now, my tests for updating with invalid parameters are failing.
tests in subgroups_controller_spec.rb
let(:invalid_attributes) {
{name: nil, group_id: nil}
}
context "with invalid params" do
it "assigns the subgroup as #subgroup" do
subgroup = Subgroup.create! valid_attributes
puts "param: #{subgroup.to_param}, id: #{subgroup.id}
put :update, {:id => subgroup.to_param, :subgroup => invalid_attributes}, valid_session
expect(assigns(:subgroup)).to eq(subgroup)
end
it "re-renders the 'edit' template" do
subgroup = Subgroup.create! valid_attributes
put :update, {:id => subgroup.to_param, :subgroup => invalid_attributes}, valid_session
expect(response).to render_template("edit")
end
end
error message:
1) SubgroupsController PUT #update with invalid params assigns the subgroup as #subgroup
Failure/Error: put :update, {:id => subgroup.to_param, :subgroup => invalid_attributes}, valid_session
ActionView::Template::Error:
No route matches {:action=>"show", :controller=>"groups", :id=>nil, :locale=>nil}
But puts "param: #{subgroup.to_param}, id: #{subgroup.id}" prints param: 1, id: 1 so clearly these ids are not nil.
rake routes:
subgroups GET (/:locale)/subgroups(.:format) subgroups#index
POST (/:locale)/subgroups(.:format) subgroups#create
new_subgroup GET (/:locale)/subgroups/new(.:format) subgroups#new
edit_subgroup GET (/:locale)/subgroups/:id/edit(.:format) subgroups#edit
subgroup GET (/:locale)/subgroups/:id(.:format) subgroups#show
PATCH (/:locale)/subgroups/:id(.:format) subgroups#update
PUT (/:locale)/subgroups/:id(.:format) subgroups#update
DELETE (/:locale)/subgroups/:id(.:format) subgroups#destroy
p.s. there are locales listed in the routes but I removed them for easier viewing. I don't think locales is this issue as update needs an :id to update.
The problem is not with your put route, with the in the rendering that it's doing. You're getting a template error and the error specifics show that you're trying to do a show on groups. Check your layout for paths that are used.

ActionController::UrlGenerationError: error No routes matches

I get the below error ActionController::UrlGenerationError.
ActionController::UrlGenerationError:
No route matches {:action=>"/accounts/100", :controller=>"accounts"}
Below is my code which throws this error.
it "can find an account" do
Account.should_receive(:find, with: {id: 2055, authorization: #auth}
get "/accounts/100", nil, {"AUTH_TOKEN" => #auth}
hashed_response = {
"#type" => "test",
"createdAt" => "2014-07-24T15:26:49",
"description" => "Something about test",
"disabled" => false
}
expect(response.status).to eq 200
expect(response.body).to eq(hashed_response.to_json);
end
I did a google on this and came to know that there is no routes defined for this. Below is my config/routes.rb file
Rails.application.routes.draw do
resources :accounts do
resources :holders
end
end
I presume this error is coming from a controller spec? If so, you simply use a symbol representing the action you want to call, not the URL itself.
eg. this is a show action, so you would use:
get :show, id: 100

Problem with routes in functional testing

I'm making a simple test project to prepare myself for my test.
I'm fairly new to nested resources, in my example I have a newsitem and each newsitem has comments.
The routing looks like this:
resources :comments
resources :newsitems do
resources :comments
end
I'm setting up the functional tests for comments at the moment and I ran into some problems.
This will get the index of the comments of a newsitem. #newsitem is declared in the setup ofc.
test "should get index" do
get :index,:newsitem_id => #newsitem
assert_response :success
assert_not_nil assigns(:newsitem)
end
But the problem lays here, in the "should get new".
test "should get new" do
get new_newsitem_comment_path(#newsitem)
assert_response :success
end
I'm getting the following error.
ActionController::RoutingError: No route matches {:controller=>"comments", :action=>"/newsitems/1/comments/new"}
But when I look into the routes table, I see this:
new_newsitem_comment GET /newsitems/:newsitem_id/comments/new(.:format) {:action=>"new", :controller=>"comments"}
Can't I use the name path or what I'm doing wrong here?
Thanks in advance.
The problem is in the way your test specifies the URL. The error message is:
No route matches {:controller=>"comments", :action=>"/newsitems/1/comments/new"}
and of course there is no action called "/newsitems/1/comments/new". You want to pass the hash { :controller => :comments, :action => :new, :news_item_id => 1 }.
The right syntax is simply:
get :new, :news_item_id => 1
(Assuming Rails 3)
Try this in your routes.rb
GET 'newsitems/:newsitem_id/comments/new(.:format)' => 'comments#new', :as => :new_newsitem_comment

Resources