Testing Destroy Action in Rails API Controller - ruby-on-rails

I'm building a RESTful JSON API with Rails 4.0 and using mongoid as my database. I'm testing the destroy action for one of my controllers using RSpec. However, when I run my test I receive the ActionController::UrlGenerationError: as Rails is unable to find a corresponding route. The weird thing is my destroy action is clearly defined in my routes.rb file and my other controller actions within the same resource work fine.
describe "DELETE 'delete credit cards'" do
before do
#credit = CreditCard.new(cc_last4: Random.rand(1234) )
end
it "should return a successful json response" do
params = {comicbook_uid: #user.comicbook_uid.to_s ,
notebook_token: #user.comicbook_token,
cc_id: #credit.id, format: :json }
delete :destroy, params
body_hash = JSON.parse response.body
expect(body_hash["success"]).to eql true
end
The error that gets generated in my terminal is this:
Failure/Error: delete :destroy, params
ActionController::UrlGenerationError:
No route matches {:comicbook_uid=>"52decf924761625bdf000000", :comicbook_token=>"sfsakjhfk",
:cc_id=>BSON::ObjectId('52decf924761625bdf020000'),
:format=>:json, :controller=>"credit_cards",
:action=>"destroy"}
My routes for the credit card resource look like this:
resources :credit_cards, only: [:create, :index, :destroy],
:defaults => { :format => 'json'}
Thank you in advance and hope can help me out soon!

You aren't passing an id attribute, which is the only param you should actually need. Moreover, since you are creating your #credit object using CreditCard.new(...) it won't actually have an id until you persist it to the db.
Replace:
it "should return a successful json response" do
params = {comicbook_uid: #user.comicbook_uid.to_s ,
notebook_token: #user.comicbook_token,
cc_id: #credit.id, format: :json }
with:
it "should return a successful json response" do
params = {id: #credit.id, format: :json }
and make sure to persist the CreditCard (or set mock expectations for it to be destroyed).

Related

RSpec No route matches {:action=>"/dashboard/sites/24/attendance_summer_city_camp_integrativ.xlsx", :controller=>"dashboard/sites"}

I have a controller /dashboard/sites_controller.rb, within which I have an action attendance_summer_city_camp_integrativ
def attendance_summer_city_camp_integrativ
#site = Site.find(params[:site_id])
respond_to do |format|
format.xlsx
end
end
It returns an Excel, as you can see.
config/routes.rb
namespace :dashboard do
resources :sites do
get :attendance_summer_city_camp_integrativ
end
end
In my test file, when I do a get request on this address I get
No route matches {:action=>"/dashboard/sites/24/attendance_summer_city_camp_integrativ.xlsx", :controller=>"dashboard/sites"}
describe 'GET #attendance_summer_city_camp_integrativ' do
subject do
get dashboard_site_attendance_summer_city_camp_integrativ_path(site.id, format: :xlsx)
end
end
Failure/Error: get dashboard_site_attendance_summer_city_camp_integrativ_path(site.id, format: :xlsx)
ActionController::UrlGenerationError:
No route matches {:action=>"/dashboard/sites/24/attendance_summer_city_camp_integrativ.xlsx", :controller=>"dashboard/sites"}
When I go to this address manually in the browser it works fine.
Started GET "/dashboard/sites/6/attendance_summer_city_camp_integrativ.xlsx" for 127.0.0.1 at 2019-06-28 18:18:46 +0200
Processing by Dashboard::SitesController#attendance_summer_city_camp_integrativ as XLSX
What am I doing wrong?
Perhaps this:
describe 'GET #attendance_summer_city_camp_integrativ' do
subject do
get dashboard_site_attendance_summer_city_camp_integrativ_path(site.id, format: :xlsx)
end
end
Should be more like this:
describe 'GET #attendance_summer_city_camp_integrativ' do
subject do
get attendance_summer_city_camp_integrativ, {site_id: site.id, format: :xlsx}
end
end
(I guess, according to the docs, you may need to form your params differently for rails 5 v. pre-rails 5.)
You have an action called attendance_summer_city_camp_integrativ, but your test is trying to call the action /dashboard/sites/24/attendance_summer_city_camp_integrativ.xlsx. Which isn't an action, but a fully-formed url. So, maybe calling get dashboard_site_attendance_summer_city_camp_integrativ_path instead of get attendance_summer_city_camp_integrativ is the issue?

rspec controller put update test not working

I am stuck on a rspec test that is testing a update method in my controller. I am getting a routing error. Hoping someone smarter than I can help. I have googled and read many post on this site, but none have turned on the light-bulb in my head.
Note: this works when finding and updating a record via the browser. Just cannot figure out the test for it.
My Route for this controller update method:
PUT /admins/project_codes/:id(.:format) admins/project_codes#update
My controller update method:
def update
#project_code = ProjectCode.find(params[:project_code][:id])
if #project_code.update_attributes(params[:project_code])
redirect_to(:action => :show, :id => params[:project_code][:id])
else
redirect_to(:action => :edit, :id => params[:project_code][:id], :notice => "Your record for #{params[:project_code][:code]} could not be updated at this time.")
end
end
The edit form is using name="project_code[...]" for fields: i.e:
<input id="project_code_code" name="project_code[code]" size="10" type="text" value="F-UZBEKIST" /
So, in my test, I need create a record, then update a field and pass it to my update method. I'm trying to create the params[:project_code] to pass to the method.
spec:
describe "PUT #update" do
it "updates with valid name change" do
code = FactoryGirl.create(:project_code)
code.name = "new-name"
put :update, :project_code => code.attributes
...
end
end
My error:
1) Admins::ProjectCodesController PUT #update updates with valid name change
Failure/Error: put 'update', :project_code => code.attributes
ActionController::RoutingError:
No route matches {:project_code=>{"id"=>"10375", "code"=>"ABCDEFG", "name"=>"new-name", "update_by"=>"jdc44", "created_at"=>"2015-10-07 13:22:31 -0400", "updated_at"=>"2015-10-07 13:22:31 -0400"}, :controller=>"admins/project_codes", :action=>"update"}
Any help would be appreciated.
It seems your PUT /admins/project_codes/:id(.:format) requires an :id parameter in the url, try sending the following:
put :update, :id => code.id, :project_code => code.attributes

Testing POST #create in RSpec with nested attributes - can't get params hash correct

Have been spending some months trying to grok RSpec/TDD. Running into some challenges testing a controller with a nested attribute. I'm a bit fuzzy about how to properly set up and pass the parameters to the controller. I can build the controller so that it actually works as expected in the browser - I just can't seem to reverse engineer a test to confirm that.
Would appreciate any recommendations to a) fix the test below, and b) advise any better ways to do it (e.g. with mocks, stubs, etc).
Here's the basic model structure:
class School < ActiveRecord::Base
has_many :scholarships
end
class Scholarship < ActiveRecord::Base
belongs_to :school
end
I've configured the routes.rb as you'd expect, with:
resources :schools do
resources :scholarships, only: [:new, :create, :destroy]
end
In the controller, #new and #create are pretty standard for a Rails app:
class ScholarshipsController < ApplicationController
def new
#school = School.find(params[:school_id])
#scholarship = #school.scholarships.build
end
def create
#school = School.find(params[:school_id])
#scholarship = #school.scholarships.create(scholarship_params)
if #scholarship.save
flash[:success] = 'Scholarship created!'
redirect_to #school
else
render 'new'
end
end
private
def scholarship_params
params.require(:scholarship).permit(:name, ** Lots of params omitted for brevity **,
:notes, school: [:id])
end
end
The spec is where I can't seem to figure things out. For spec/controllers/scholarships_controller_spec.rb:
require 'rails_helper'
describe ScholarshipsController, type: :controller do
describe 'POST #create' do
context 'with valid attributes' do
before :each do
#school = create(:school)
#scholarship = #school.scholarships.create(FactoryGirl.build(:scholarship).attributes)
end
it 'receives :save' do
post :create, { scholarship: #scholarship.attributes, school: #school.id }
expect(#scholarship).to receive(:save)
end
end
end
end
When I run that test, I get the following error:
Failures:
1) ScholarshipsController POST #create with valid attributes receives :save
Failure/Error: post :create, scholarship: { attributes: #scholarship.attributes, school: #school.id } #school_id: #school.id, scholarship: #scholarship
ActionController::UrlGenerationError:
No route matches {:action=>"create", :controller=>"scholarships",
:scholarship=>{"id"=>"1", "name"=>"Dynamic Metrics Director Scholarship", *** Lots of parameters omitted for brevity ***
, "school_id"=>"2"}, :school=>"2"}
The parameters look correct to me. there's a set of attributes for the scholarship, and for the school. But the routing isn't working. I've tried a dozen different ways to try and get this to work. Heartened that I'm apparently passing a (more or less correct) parameters hash, but can't figure out quite where I'm going wrong.
****** EDIT ******
Updated in response to an answer posted below.
Changed the syntax of the spec as suggested by Srdjan:
it 'receives :save' do
post :create, "schools/#{#school.id}/scholarships", { scholarship: #scholarship.attributes, school_id: #school.id }
expect(#scholarship).to receive(:save)
end
This changes the error message. I assume that indicates that the parameters are being passed correctly, since it's no longer throwing an error related to routes/params..? Error message is:
1) ScholarshipsController POST #create with valid attributes receives :save
Failure/Error: expect(#scholarship).to receive(:save)
(#<Scholarship:0x007fe293b02598>).save(*(any args))
expected: 1 time with any arguments
received: 0 times with any arguments
Just for good measure, here are the relevant routes, which I hadn't posted previously:
school_scholarships POST /schools/:school_id/scholarships(.:format) scholarships#create
new_school_scholarship GET /schools/:school_id/scholarships/new(.:format) scholarships#new
school_scholarship DELETE /schools/:school_id/scholarships/:id(.:format) scholarships#destroy
In your test, you're POST-ing to the wrong route. As setup in routes.rb, scholarship resources do not exist out of the context of a school resource.
In order to fix this, you have to answer a question: "Does it make sense for a user to access a scholarship record without having to specify a school?"
If the answer is yes, you can either copy the scholarships route and paste them outside of the schools resource block. This way, you can have access to scholarships without having to specify a school, but also with specifying a school.
If the answer to the question is no, then you need to fix your test as such:
it 'receives :save' do
post :create, "schools/#{#school.id}/scholarhips", { scholarship: #scholarship.attributes, school_id: #school.id }
expect(#scholarship).to receive(:save)
end

Pass Form Vars in Rspec to Update Method

I'm still fairly new to the rspec way. I've read many posts on a redirect_to but cannot seem to get passed this error. I'm trying to simulate the passing of form variable/value in my rspec test, but getting a routing error. I'm converting tests to rspec tests on an app that is live and working.
In my employees_micros_controller.rb, I have an update method that expects params[:employees_micro][:id]. My question is How do I simulate this in my rspec test?
Controller:
def update
#em = nil
# check for id from form
if params[:employees_micro][:id]
#em = EmployeesMicro.find_by_id(params[:employees_micro][:id])
end
....
end
Rspec Test: note: ### error line ###
# update and redirect
describe 'POST #update' do
it "updates employee_micro and redirect to employee_details" do
# #emp_micros set in before(each) above
#emp_micros.home_job = 123
# update method looks for params[:employees_micro][:id]
post :update, :employees_micro => { :id => #emp_micros } ### error line ###
expect(response).to redirect_to("employee_details_employee_path")
end
end
Error:
Failure/Error: post :update, :employees_micro => { :id => #emp_micros }
ActionController::RoutingError:
No route matches {:employees_micro=>{:id=>"11960"}, :controller=>"employees_micros", :action=>"update"}
Is my >> post :update line syntax correct?
I do not understand the routing error. I'm only trying to simulate passing a form variable to the update method from my test. If I remove everything after the post/put line, I still get the same error, so it is definitely on that line.
I've also tried using "put" in place of "post" in the test. It nets me the same error.
Thanks for any tips or advice.
The update route expects the :id param to be at the top level, so use:
post :update, :id => #emp_micros, :employees_micro => { <other attributes to update> }

How can I test a Rails RESTful API post request with xml as input?

I am adding a RESTful API to the Rails Tutorial sample app. The controller actions should take XML as input and respond with XML. I am trying to follow a TDD approach but have been unable to find a definitive method of making a post request. Here are my tests, as best as I've written them so far:
it "should increment the Relationship count" do
expect do
# valid_xml = "<xml><:followed_id>#{other_user.id}</:followed_id></xml>"
valid_xml = { followed_id: other_user.id }.to_xml
post :create, relationship: valid_xml, format: 'xml', content_type: 'application/xml'
end.to change(Relationship, :count).by(1)
end
it "should respond with success" do
# valid_xml = "<xml><:followed_id>#{other_user.id}</:followed_id></xml>"
valid_xml = { followed_id: other_user.id }.to_xml
post :create, relationship: valid_xml, format: :xml, content_type: 'application/xml'
expect(response).to be_success
end
This particular test is verifying that posting XML will create a new Relationship. As you can see, I have tried several ways to specify that the input is XML. Here is the controller action:
class RelationshipsController < ApplicationController
before_action :signed_in_user
respond_to :html, :js, :xml
def create
# Problem is that the xml is not being read as such; it's a string
relationship = params[:relationship]
puts relationship
puts relationship[:followed_id]
#user = User.find(relationship[:followed_id])
current_user.follow!(#user)
respond_with #user
end
For the given tests, the controller prints out relationship as XML but errors on the following line, where it attempts to get the value of key :followed_id. The error is TypeError: no implicit conversion of Symbol into Integer for both tests.
I assume that this means that the type of relationship is a string, not a hash, and Ruby thinks that the bracket is supposed to be an index. Does anyone know where I am going wrong, either in the test or the controller action?
Are there any better ways to test a RESTful API or gems I should use?
The XML parameters parser was removed from core in Rails 4.0. This was due to several vulnerabilities and the fact that most APIĀ“s worth using today are JSON or moving towards JSON.
The removed functionality is available from the actionpack-xml_parser gem.

Resources