Spec - simple json api call - ruby-on-rails

I just want to test that a controller method is passing an int.
Test:
it 'responds successfully with mocked fto hours remaining' do
get :fto_hours_remaining, {}, { "Accept" => "application/json" }
json = JSON.parse(response.body)
expect(json['hours_remaining']).to be_100
end
Controller method (I tried the commented out block too):
def fto_hours_remaining
#fto_hours_remaining = 100
render json: #fto_hours_remaining
# respond_to do |format|
# format.json { render :json => {:hours_remaining => #fto_hours_remaining} }
# end
end
I get the error: JSON::ParserError: 757: unexpected token at '100' with the error pointing to json = JSON.parse(response.body)
Anybody see a mistake? Thanks.

So you have right version in your controller:
def fto_hours_remaining
#fto_hours_remaining = 100
render :json => { :hours_remaining => #fto_hours_remaining }
end
Your action now render just string 100 this is invalid json.
Try in irb:
=> require 'json'
=> true
=> JSON.parse "100"
=> JSON::ParserError: 757: unexpected token at '100'
render( json: { hours_remaining: #fto_hours_remaining } ) means render me in json format this hash { hours_remaining: #fto_hours_remaining } that should be valid json:
{
"hours_remaining": 100
}
And your test:
# return string "100"
number = json['hours_remaining']
# fails beacause "100" != 100
expect(json['hours_remaining']).to be_100
# try this
expect(json['hours_remaining']).to eq("100")

Related

Rendering Two JSON Items In Rails

This seems like a duplicate question but the answers on the others posts don't seem to work for my issue here.
I'm needing to render two JSON items here within my index method in my controller:
def index
#user = User.all
#libraries = Library.all.order(:created_at)
user_cards = current_user.libraries
render :json => #libraries, :include => :user
render :json => user_cards
end
I attempted to do it this way (failed with a 500 error):
render :json => #libraries, user_cards, :include => :user
And I also attempted to do it this way (also failed with a 500 error): render :json => #libraries :include => [:user, :user_cards]
UPDATE
This is the most recent attempt as rendering the json properly:
def index
#user = User.all
#libraries = Library.all.order(:created_at)
user_cards = current_user.libraries
render json: {
user_cards: user_cards,
libraries: #libraries.as_json(include: [:user])
}
end
The issue with this is that I am now getting an error on libraries throughout my application as it stands. If I simply just render json like I originally had it (render :json => #libraries, :include => :user), I do not get this error. So, I'm assuming the way I have it is still not correct. The exact error on libraries is being called within one of my React components where I use filter:
Error: Uncaught TypeError: this.props.librarys.filter is not a function
Error Location:
let filteredCards = this.props.librarys.filter(
(library) => {
return library.title.toLowerCase().indexOf(this.state.search.toLowerCase()) !== -1 || library.desc.toLowerCase().indexOf(this.state.search.toLowerCase()) !== -1
}
)
Controller can only return one response, you can achieve this with combining this two returns into one:
respond_to do |format|
format.json { render json: { user_cards: user_cards,
libraries: #libraries } }
end

OLA API integration in Ruby on Rails web API {"code":"invalid_partner_key","message":"Partner key is not authorized"}

I am passing the basic URL required to call OLA API with x app token in HTTParty, but it gives this error:
{"code":"invalid_partner_key","message":"Partner key is not authorized"}
Here is the code:
require 'rubygems'
require 'httparty'
class ProductsController < ApplicationController
def index
lat = params[:lat].to_s
long = params[:long].to_s
#results = HTTParty.get("https://api.uber.com/v1/products?server_token=my_token&latitude="+lat+"&longitude="+long).parsed_response
#result1 = HTTParty.get("https://devapi.olacabs.com/v1/products?X-APP-TOKEN=my_token&pickup_lat=12.9491416&pickup_lng=77.64298").parsed_response
respond_to do |format|
format.json { render :json => JSON.parse(#results) }
format.json { render :json => JSON.parse(#result1) }
format.html { render "index.html.erb" }
end
end
end
Why is this happening, and how do I fix it?
Going through the olacabs docs, your X-APP-TOKEN should be passed as a header and not along with the payload. So you should be doing something like this
query = {
"pickup_lat" => 12.9491416,
"pickup_lng" => 77.64298
}
headers = {
"X-APP-TOKEN" => your_token
}
#result1 = HTTParty.get(
"https://devapi.olacabs.com/v1/products",
:query => query,
:headers => headers
).parsed_response
I didn't test this out but should give a good start to figuring your issue out.

Boolean not behaving correctly

I'm making an ajax call to this method
def check_solution
puzzle = Puzzle.find(params[:id])
solved = puzzle.grid.solution == params[:solution].to_s
solved_before = params[:solved_before]
puts !solved_before
if(solved && !solved_before)
Puzzle.find(params[:id]).increment!(:times_solved, by =1)
end
respond_to do |format|
response = { :status => "ok", :message => "Success!", :html => solved}
format.json { render json: response }
end
end
The parameters going in from my local server are
Parameters: {"solution"=>"0001000010110011001100000", "solved_before"=>"false", "id"=>"3758"}
Why, when I print out !solved_before with puts, does it say false instead of true?
That's because solved_before comes in as a string and not as a boolean.

How to pass json response back to client

In my ruby on rails code I want to send back json response to client. Since I am new to ruby on rails I do not know how can I do this. I want to send error = 1 and success = 0 as json data if data does not save to database and if it successfully saves that it should send success = 1 and error = 0 Please see my code below
here is my controller
class ContactsController < ApplicationController
respond_to :json, :html
def contacts
error = 0
success = 1
#contacts = Contact.new(params[:contact])
if #contacts.save
respond_to do |format|
format.json { render :json => #result.to_json }
end
else
render "new"
end
end
end
here is my javascript code
$('.signupbutton').click(function(e) {
e.preventDefault();
var data = $('#updatesBig').serialize();
var url = 'contacts';
console.log(data);
$.ajax({
type: 'POST',
url: url,
data: data,
dataType: 'json',
success: function(data) {
console.log(data);
}
});
});
There are tons of other elegant ways, but this is right:
class ContactsController < ApplicationController
def contacts
#contacts = Contact.new(params[:contact])
if #contacts.save
render :json => { :error => 0, :success => 1 }
else
render :json => { :error => 1, :success => 0 }
end
end
end
Add also a route to routes.rb. If you need to use html response you have to include respond_to do |format|.
You have to adjust your routes to accept json data
match 'yoururl' => "contacts#contacts", :format => :json
Then it will work

How to join/merge xml files into a single file and return it?

I'm using the Last.fm API and I'm trying to get a lot of info about a certain user and returning it in xml. So, here's the call in my view:
<%= form_tag fetch_user_path, :remote => true, :'data-type' => 'xml', :id => 'search' do %>
<%= text_field_tag :q %>
<% end %>
So, as you can see, it's expecting XML, and I'm correctly handling the callback using jQuery. Then, in my controller:
# fetch_controller.rb
def user
username = params[:q].gsub(' ','+')
get_info_url = "http://ws.audioscrobbler.com/2.0/?method=user.getinfo&user=#{username}&api_key=#{API_KEY}"
get_friends_url = "http://ws.audioscrobbler.com/2.0/?method=user.getfriends&user=#{username}&api_key=#{API_KEY}"
respond_to do |format|
format.xml {
begin
#info = Nokogiri::XML(open(get_info_url))
#friends = Nokogiri::XML(open(get_friends_url))
rescue Exception => e
if e.message == '400 Bad Request'
render xml: { :error => 'User not found.' }, :status => 400
else
render xml: { :error => 'Connection to Last.fm failed.' }, :status => 500
end
else
# Here, I want to render #info + #friends!
render xml: #info
end
}
end
This way, I'm correctly returning the xml returned by get_info_url. However, I want to join that xml to the xml returned by get_friends_url. How would I go about that?
Following Ben Miller's answer, I'm getting a parserror on my callback. I think it's got to to do with both xml files containing xml version. And maybe the combined file does not? I'm seeing that the xml files are being concatenated, here's how they look using console.log:
Error: Invalid XML: <?xml version="1.0"?>
<Combined>
<UserInfo>
<?xml version="1.0" encoding="utf-8"??>
<lfm status="ok">
<user>
# lots of info about the user
</user>
</lfm>
</UserInfo>
<FriendInfo>
<?xml version="1.0" encoding="utf-8"??>
<lfm status="ok">
<friends for="user" page="1" perpage="50" totalpages="2" total="96">
# lots of info about the user's friends
</friends>
</lfm>
</FriendInfo>
</Combined>
One option it so convert the two XML object to a string and concat them, then wrap in a new root node.
Or you could do it with Nokogiri builder
def user
username = params[:q].gsub(' ','+')
get_info_url = "http://ws.audioscrobbler.com/2.0/?method=user.getinfo&user=#{username}&api_key=#{API_KEY}"
get_friends_url = "http://ws.audioscrobbler.com/2.0/?method=user.getfriends&user=#{username}&api_key=#{API_KEY}"
respond_to do |format|
format.xml {
begin
info_xml = Nokogiri::XML(open(get_info_url))
friends_xml = Nokogiri::XML(open(get_friends_url))
builder = Nokogiri::XML::Builder.new do |xml_out|
xml_out.Combined {
xml_out.UserInfo {
node = info_xml.at_xpath("//user")
xml_out << node.to_xml.to_str
}
xml_out.FriendInfo {
node = friends_xml.at_xpath("//friends")
xml_out << node.to_xml.to_str
}
}
end
rescue Exception => e
if e.message == '400 Bad Request'
render xml: { :error => 'User not found.' }, :status => 400
else
render xml: { :error => 'Connection to Last.fm failed.' }, :status => 500
end
else
render xml: builder.to_xml
end
}
end
end

Resources