Using Postmates API in a rails app with HTTParty - ruby

I've been working on integrating Postmates with my ecommerce rails application for on demand deliveries. I've built a controller and view for testing purposes and configured it in my routes file (built in my dev environment). For reference, here is the documentation from Postmates: docs and here is a technical blogpost: blog
Routes file:
resources :postmates do
member do
post 'get_delivery'
end
end
The controller:
require 'httparty'
require 'json'
class PostmatesController < ApplicationController
def get_delivery
api_key = **hidden**
#customer = 'cus_K8mRn4ovuNyNKV'
#urlstring_to_post = 'https://api.postmates.com/v1/customers/' + #customer + '/delivery_quotes'
#result = HTTParty.post(#urlstring_to_post.to_str,
:body => { :dropoff_address => "205 E 95th Street, New York, NY 10128",
:pickup_address => "619 W 54th St, New York, NY 10019"
}.to_json,
:basic_auth => { :username => api_key },
:headers => { 'Content-Type' => 'application/json' })
end
end
The view:
<div class="container">
<%= form_tag url_for(:controller => 'postmates', :action => 'get_delivery'), :method => 'post' do %>
<%= submit_tag "Get Delivery", :action => 'get_delivery', :controller => 'postmates'%>
<% end %>
</div>
<p>Result: <%= #result %></p>
Here is the response back from the api:
{"kind"=>"error", "code"=>"invalid_params", "params"=>{"dropoff_address"=>"This field is required.", "pickup_address"=>"This field is required."}, "message"=>"The parameters of your request were invalid."}
It seems to me that the dropoff and pickup address are not being submitted in the HTTP request. Can anyone tell me if I'm making some minor syntax error or something? The fact that I'm getting this response means that my authentication is fine and so is the url. Any ideas?
Thanks.

It looks like you're posting JSON data to the API, while the documentation (https://postmates.com/developer/docs#basics) says you should POST the data as application/x-www-form-urlencoded
I'm not really familiar with HTTParty, but you can probably just remove the .to_json and don't specify the content-type header.

Unrelated to your question, but you shouldn't publicly post your API key. ;)

Related

Cross-Origin Request Blocked after installing the CORS gem: when trying to use PUSHER for pop up notification in a blog application

config/application.rb file
require File.expand_path('../boot', __FILE__)
require 'rails/all'
Bundler.require(*Rails.groups)
module Blog
class Application < Rails::Application
config.middleware.insert_before 0, "Rack::Cors", :debug => true, :logger => (-> { Rails.logger }) do
allow do
origins '*'
resource '/cors',
:headers => :any,
:methods => [:post],
:credentials => true,
:max_age => 0
resource '*',
:headers => :any,
:methods => [:get, :post, :delete, :put, :options, :head],
:max_age => 0
end
end
end
end
pusher_controller.rb
pusher api is used for the pop up notofocation as said in takeofflabs.com
class PusherController < ApplicationController
def auth
if current_user && params[:channel_name]=="private-user-current-#{current_user_id}"
response = Pusher[params[:channel_name]].authenticate(params[:socket_id])
render :json => response
else
render "not_authorized" , :status =>'403'
end
end
def show
Pusher.app_id = PUSHER_APP_ID
Pusher.key = PUSHER_KEY
Pusher.secret = PUSHER_SECRET
x= render_to_string(:partial => "/views/notifications/notification")
Pusher["private-user-#{#notification.user_id}"].trigger('new-notification',x)
end
end
environment.rb file
require File.expand_path('../application', FILE)
PUSHER_APP_ID = "101053"
PUSHER_KEY = "89979ad24549eabc3764"
PUSHER_SECRET = "f4c1a6ca70d523e9e72e"
application.html.erb
<html>
<head>
<title>Blog</title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
<%= javascript_include_tag "http://js.pusherapp.com/2.2/pusher.min.js" %>
<script>
var pusher = new Pusher("#{PUSHER_KEY}");
var userChannel = pusher.subscribe("private-user-#{current_user.id}");
userChannel.bind('new-notification', function(message) {
$(".notifications_area").html(message);
});
</script>
</head>
<body>
<%if current_user %>
Logged in as: <%= current_user.email if current_user %>
<%else%>
PLEASE LOG IN TO SEE THE ARTICLES
<%end%>
<%= yield %>
</body>
</html>
Rails.application.initialize!
Although your question doesn't directly say this I'm assuming that the CORS error occurs when the private channel subscription authentication is taking place.
I'm not too familiar with Rack CORS however the way these things usually work is that they require an authentication token to be passed with any request to the server. The way to do this in with the Pusher JavaScript library is to pass in an auth option when you construct the Pusher instance:
var options = {
auth: {
headers: {
'x-domain-token': YOUR_CORS_TOKEN
}
}
};
var pusher = new Pusher( YOUR_APP_KEY, options );
You will need to check:
Where Rack CORS expects the token to be. It may be in a header or as a POST or GET parameter. You can also set these via options
What the name of the parameter is. Above I've guessed at x-domain-token
For information on options see the Pusher docs on the options.auth parameter.
There is also a Pusher CSRF RoR FAQ which may provide additional insight.

400 Bad Request Nestful Ruby

I'm trying to use the Pocket API to authorize my application. So I'm using Nestful to send HTTP requests. And everytime I try sending a request I get a 400 Bad Request. The Pocket documentation says that it could be that it's either a missing consumer key or a missing redirect url.
But now I'm looking at the network tab in Chrome and it says that there is a 500 Internal Service Error. What are these things, and how can I fix them?
My code:
require "nestful"
require "sinatra"
require "uri"
get '/' do
params = {
:consumer_key => '******************************',
:redirect_uri => 'http://localhost:4567/callback'
}
response = Nestful.post 'https://www.getpocket.com/v3/oauth/request',
:params => params,
:format => :json
response.body
response.headers
end
get '/callback' do
"hello world"
end
So I got help on my problem. It turns out that params was already a hash, and so I did not need to say :params => params because that would be redundant.
Before
response = Nestful.post 'https://www.getpocket.com/v3/oauth/request',
:params => params,
:format => :json
After
response = Nestful.post 'https://getpocket.com/v3/oauth/request',
params,
:format => :json

Weird behavior Pony mail Sinatra

I can send mail from my site fine using Sinatra and Pony mail.The problem lies in setting the body to use an erb template.
So my config is set like so
post '/' do
from = params[:name]
subject = "#{params[:name]} has contacted you"
body = erb(:mail)
Pony.mail(
:from => from,
:to => ENV["EMAIL_ADDRESS"],
:subject => subject,
:body => body,
:via => :smtp,
:via_options => {
:address => 'smtp.gmail.com',
:port => '587',
:enable_starttls_auto => true,
:user_name => ENV["USER_NAME"],
:password => ENV["PASSWORD"],
:authentication => :plain,
:domain => "localhost.localdomain"
})
flash[:notice] = "Thanks for your email. I will be in touch soon."
redirect '/success'
So my subject renders correclty, but the body of the message is actually returned as the html source for my webpage (as if i had right clicked view source)
My erb template is like so
Hello Rich,
Seems as if you have recieved an email from <%= params[:name] %> via your website.
Their email address is <%= params[:email] %>, this is what they said.
<%= params[:message] %>
So why isnt the body rendering the erb tempalte?
Im a bit confused here? Have i set something up incorrectly within the erb template?
Thanks
Ok so for anyone else with same issue what i needed to do was tell sinatra not to use my layout file, so when setting
body = erb(:mail)
It needed to be
body = erb(:mail, layout: false )

jQuery Mobile breaks Rails respond_to when using UJS remote links accept headers

I'm converting our Rails 3 web app to use jQuery mobile, and I'm having problems with "remote" links.
I have the following link:
= link_to "Text", foo_url, :method => :put, :remote => true
Which, on the server, I'm handling like this:
respond_to do |format|
if foo.save
format.html { redirect_back_or_to blah_url }
format.json { render :json => {:status => "ok"} }
end
end
This used to work wonderfully. However, since I've added jQuery Mobile, the controller code goes through the "html" branch instead of the "json" one, and responds with a redirect.
I've tried adding
:data => { :ajax => "false" }
to the link, but I get the same effect.
Before jQuery Mobile, UJS was sending the request with the following accept header:
Accept:application/json, text/javascript, */*; q=0.01
while with jQuery Mobile, I'm getting this header:
Accept:*/*;q=0.5, text/javascript, application/javascript, application/ecmascript, application/x-ecmascript
I believe this change in headers is the culprit of the change in server-side behaviour. I haven't been able to debug through the client side to figure out who's doing what exactly. UJS is clearly still doing something, since I'm getting a "PUT request" of sorts, things get routed appropriately, etc, but I'm not sure what's changing the headers.
Thank you!
Daniel
By default remote: true goes to the format.js clause (and searches for some .js.erb template to send back), and defaults to format.html and sends back the html template.
You should use ”data-type” => :json in your link_to call if you want to return json, like:
<%= link_to 'Show Full Article', #article, :remote => true, "data-type" => :json %>
Source: http://tech.thereq.com/post/17243732577/rails-3-using-link-to-remote-true-with-jquery-ujs

Stubbing RestClient response in RSpec

I have the following spec...
describe "successful POST on /user/create" do
it "should redirect to dashboard" do
post '/user/create', {
:name => "dave",
:email => "dave#dave.com",
:password => "another_pass"
}
last_response.should be_redirect
follow_redirect!
last_request.url.should == 'http://example.org/dave/dashboard'
end
end
The post method on the Sinatra application makes a call to an external service using rest-client. I need to somehow stub the rest client call to send back canned responses so I don't have to invoke an actual HTTP call.
My application code is...
post '/user/create' do
user_name = params[:name]
response = RestClient.post('http://localhost:1885/api/users/', params.to_json, :content_type => :json, :accept => :json)
if response.code == 200
redirect to "/#{user_name}/dashboard"
else
raise response.to_s
end
end
Can someone tell me how I do this with RSpec? I've Googled around and come across many blog posts which scratch the surface but I can't actually find the answer. I'm pretty new to RSpec period.
Thanks
Using a mock for the response you can do this. I'm still pretty new to rspec and test in general, but this worked for me.
describe "successful POST on /user/create" do
it "should redirect to dashboard" do
RestClient = double
response = double
response.stub(:code) { 200 }
RestClient.stub(:post) { response }
post '/user/create', {
:name => "dave",
:email => "dave#dave.com",
:password => "another_pass"
}
last_response.should be_redirect
follow_redirect!
last_request.url.should == 'http://example.org/dave/dashboard'
end
end
Instance doubles are the way to go. If you stub a method that doesn't exist you get an error, which prevents you from calling an un-existing method in production code.
response = instance_double(RestClient::Response,
body: {
'isAvailable' => true,
'imageAvailable' => false,
}.to_json)
# or :get, :post, :etc
allow(RestClient::Request).to receive(:execute).and_return(response)
I would consider using a gem for a task like this.
Two of the most popular are WebMock and VCR.

Resources