rspec controller test, get with multiple parameters - ruby-on-rails

I want to test to a controller that works on browser and looks like this
http://url.dev/jobs/1445.json?project_id=1144&accesskey=MyString
this is what i have on my controler spec file:
params = {:id=>"1445", :project_id=>1144, :accesskey=>"MyString"}
get :show, params, format: :json
On the log i see:
Processing by JobsController#show as HTML
Parameters: {"id"=>"1440"}
Why it is trying to process as HTML and not as JSON? Why it only receives the id parameter?
Also, if I do this:
get :show, id: params[:id], format: :json
It tries to process using JSON but it dont works because I need the other params.

The format: :json part must be on the 2nd argument.
This works pretty well
params = {:id=>"1445", :project_id=>1144, :accesskey=>"MyString", format: :json}
get :show, params

get only takes 2 arguments, the "action" and "args"
Your code:
get :show, params, format: :json
Is passing in 3

Related

Rails 4 and JSON routing returns error in Firebug

I have implemented an AJAX call that renders a JSON response.After checking my Firebug Console, I can see that the call results in a 404 Not Found error.
In my Controller (test_rules_controller.rb)
def rule_attributes
#test = RuleModel.find(params[:rule_model_id]).rule_attributes
respond_to do |format|
format.json { render :json => #test }
end
end
In my Routes:
get "/rule_models/:rule_model_id:/rule_attributes" => "test_rules#rule_attributes", :as => "rule_attributes", :format => :json
I have also created a rule_attributes.json.jbuilder file in my test_rules view folder:
json.rule_attributes #test
I am not sure why it is resulting in this error as I've never used JSON with routes before (Rails Newbie). When I try to navigate to the same URL in the browser, it raises the error that no route matches the given route (http://localhost:3000/rule_models/1/rule_attributes.json).
Can anybody please help?

How to use rails 'get' in a rspec test

Inside a controller spec I have the following code...
subject do
get 'index'
puts 'response is ' + response.body
JSON.parse(response.body)
end
This works fine, getting the index action for the specific api controller. However when I try a show request, I don't know how to pass in a variable, so when I run...
subject do
get 'show'
puts 'response is ' + response.body
JSON.parse(response.body)
end
I get the error...
←[31mFailure/Error:←[0m ←[31mget 'show'←[0m
←[31mActionController::RoutingError←[0m:
←[31mNo route matches {:controller=>"api/example/v1/clinics", :action=>"show"}←[0m
There is a show action for the api/example/v1/clinics, of course I didn't pass the parameter which it needs, unsure how to do that. How would I get a show action working?
I tried something like
get 'api/example/v1/clinics/2'
but that does not work either. I can't seem to locate the documentation for this rails method either. Any help is appreciated. Thanks.
For controller actions that require parameters (for example 'id' is required by the show action) you need to pass it as a parameter to the get request:
get :show, id: 1
Or if using older 1.8 hash syntax:
get :show, :id => 1
You can pass in an id to get :show by:
get 'show', id: 2

Testing Destroy Action in Rails API Controller

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).

Rails 4 - rendering JSON from a view

I'm having the worst time rendering a .json.erb file from my controller while being able to test it with RSpec. I have api_docs/index.json.erb and the following controller:
class ApiDocsController < ApplicationController
respond_to :json
def index
render file: 'api_docs/index.json.erb', content_type: 'application/json'
end
end
The explicit render file line seems unnecessary, but if I don't do that or render template: 'api_docs/index.json.erb', then I get an error about "Missing template api_docs/index". Likewise if I do have to pass the file name, it sucks even more that I have to give the exact directory--Rails should know that my ApiDocsController templates live in the api_docs directory.
If I have render file or render template, then I can visit the page and get the JSON contents of my index.json.erb file, as expected. However, this RSpec test fails:
let(:get_index) { ->{ get :index } }
...
describe 'JSON response' do
subject {
get_index.call
JSON.parse(response.body)
}
it 'includes the API version' do
subject['apiVersion'].should_not be_nil
end
end
It fails on the JSON.parse(response.body) line and if I raise response.body, it's an empty string. If I do render json: {'apiVersion' => '1.0'}.to_json in the controller, then the test passes just fine.
So, how can I always render the JSON template when I go to /api_docs (without having to put .json at the end of the URL), and in a way that works both in the browser and in my RSpec test? And can I render the template without having to have some long render call in which I pass the full path of the view?
Actually since you're already using respond_to :json in your controller you can use just a render method to choose your template and, as you probably know, if the template have the same name of the controller method you should be able to suppress the whole render method.
If you just remove the render line, what's the result?
Part of my solution was based on this answer to another question: adding defaults: {format: :json} to my routes file lets me go to /api_docs and see the JSON when the action is just def index ; end with no render. The RSpec test still fails though. The full line from my routes file: resources :api_docs, only: [:index], defaults: {format: :json}.
Thanks to this guy with the same problem and his gist, I added render_views to my describe block and got my test to pass:
describe ApiDocsController do
render_views
...
let(:get_index) { ->{ get :index } }
describe 'JSON response' do
subject {
get_index.call
JSON.parse(response.body)
}
it 'includes the API version' do
subject['apiVersion'].should_not be_nil
end
end

How do I override the RJS MIME Type in Rails 2.3?

I have an app running Rails 2.3.5 that has a JSON API for much of it.
A contractor came in and did some work on the app and used RJS in a few places. Some of those controller actions that are using RJS for the main web site also need to be part of the API.
The problem is that JSON API requests trigger the RJS responses, which is not what I want. I'd like the RJS responses to happen from a browser, but when it's an API request (as distinguished by using the "application/json" Accept and Content-Type headers) then I'd like it to just send the API response.
From what I can tell, Rails triggers an RJS response for any MIME Type that involves javascript, i.e.
text/javascript
application/json
etc.
Is there a way to force RJS to only respond to text/javascript? Or is there a better way to solve this problem?
To make it more clear, I have code that looks like this:
def show
#dashboard = #user.dashboard
respond_to do |wants|
wants.html
wants.json { render :json => #dashboard }
end
end
The trouble is, there is also a show.rjs template in the view folder for this controller. When someone hits the API, I want it to render the json results, as I have listed above, but instead, it renders the show.rjs template.
How can I make sure that API clients get the json results I want, and still let the RJS template render for people on the website?
You will need json defined in your mime_types.rb and then you should be able to do this:
def show
#dashboard = #user.dashboard
respond_to do |format|
format.html
format.json {render :json => #dashboard}
format.js
end
end
More to read here: http://ryanbigg.com/2009/04/how-rails-works-2-mime-types-respond_to/
In your controller's action try the following:
def index
respond_to do |format|
format.html # Renders index.html.erb as usual
format.xml { render :json => {:name => "raskchanky"}.to_json }
end
end
According to Rails documentation (http://api.rubyonrails.org/classes/ActionController/Base.html) "render :json" sets the content type of the response to application/json.
Are you sure that your javascript is sending the correct headers? When I do rjs, generally I do this by responding to format.js. This allows my to easily separate json and js responses.
Generally, my problems have been in ensuring that my ajax actions are actually sending requests in the proper format. When in doubt, you can add a 'format':'js' parameter to your request. In jQuery:
// try to get it to figure out rjs actions by itself
$('a').click(function(e){
e.preventDefault();
$.get({
url: this.attr('href'),
dataType: 'script',
success: responseFunction
});
});
// or force the format
$('a').click(function(e){
e.preventDefault();
$.get({
url: this.attr('href'),
data: {format: 'js'},
success: responseFunction
});
});

Resources