I have an app that is integrated with the Easypost API (for shipping stuff, really cool). I'm using their tracking information webhooks to fire events in my app. I'm using ruby case
statements to accomplish this. Here's a link to Easypost's API doc: https://www.easypost.com/docs/api#webhooks
I would like to match my case statement to the result.status key value in the JSON. Initially I was using just the description, but I need it to be more specific. Take a look:
{
"id": "evt_qatAiJDM",
"object": "Event",
"created_at": "2014-11-19T10:51:54Z",
"updated_at": "2014-11-19T10:51:54Z",
"description": "tracker.updated",
"mode": "test",
"previous_attributes": {
"status": "unknown"
},
"pending_urls": [],
"completed_urls": [],
"result": {
"id": "trk_Txyy1vaM",
"object": "Tracker",
"mode": "test",
"tracking_code": "EZ4000000004",
"status": "delivered",
"created_at": "2014-11-18T10:51:54Z",
"updated_at": "2014-11-18T10:51:54Z",
"signed_by": "John Tester",
"weight": 17.6,
"est_delivery_date": "2014-08-27T00:00:00Z",
"shipment_id": null,
"carrier": "UPS",
Here's the code I was using
class HooksController < ApplicationController
# to bypass CSRF token authenticity error
skip_before_filter :verify_authenticity_token
def stripe
#using easypost now as the webhook event
case params[:description]
# From EasyPost API https://www.easypost.com/docs/api#webhooks:
# tracker.updated: Fired when the status for the scan form changes
when 'tracker.updated'
@shipments = Spree::Shipment.where(transferred: false, state: "shipped")
@shipments.each do |shipment|
item_total = 0
shipment.line_items.each do |item|
item_total += item.product.price * item.quantity
end
transfer = Stripe::Transfer.create(
# Take 10% for ourselves from the total cost
# of items per supplier(shipment)
:amount => (item_total * (100 - shipment.supplier.commission_percentage)).floor,
:currency => "usd",
:recipient => shipment.supplier.token
)
shipment.transferred = true
shipment.save!
end
end
end
end
Since the status key is nested one level in the JSON do I need to account for that in my webhook code? Might it be case params[:status]
or case params[:result :status]?
Thanks
UPDATE
I now realize I want to use some more granular details of the EasyPost API. I need to access the status within the array of Tracking Details:
//Easypost API
{
"id": "evt_qatAiJDM",
"object": "Event",
"created_at": "2014-11-19T10:51:54Z",
"updated_at": "2014-11-19T10:51:54Z",
"description": "tracker.updated",
"mode": "test",
"previous_attributes": {
"status": "unknown"
},
"pending_urls": [],
"completed_urls": [],
"result": {
"id": "trk_Txyy1vaM",
"object": "Tracker",
"mode": "test",
"tracking_code": "EZ4000000004",
"status": "delivered",
"created_at": "2014-11-18T10:51:54Z",
"updated_at": "2014-11-18T10:51:54Z",
"signed_by": "John Tester",
"weight": 17.6,
"est_delivery_date": "2014-08-27T00:00:00Z",
"shipment_id": null,
"carrier": "UPS",
"tracking_details": [
{
"object": "TrackingDetail",
"message": "BILLING INFORMATION RECEIVED",
"status": "pre_transit",
"datetime": "2014-08-21T14:24:00Z",
"tracking_location": {
"object": "TrackingLocation",
"city": null,
"state": null,
"country": null,
"zip": null
}
So I need to access result
and then tracking_details
and then status
. this case statement: case params[:result][:tracking_details][:status]
gave me this error:
May 14 10:31:30 leemaeats app/web.1: TypeError (no implicit conversion of Symbol into Integer):
May 14 10:31:30 leemaeats app/web.1: app/controllers/hooks_controller.rb:28:in `[]'
May 14 10:31:30 leemaeats app/web.1: app/controllers/hooks_controller.rb:28:in `stripe'
Seems like it's because I need to specify the element in this array tracking_details
. Anyone know how to reference that?
Thanks
Probably case params[:result][:status]
params[:result]
returns a hash which contains, among other things, the "status"
member that you can access with [:status]
EDIT to answer UPDATE
params[:result][:tracking_details]
returns an array, so you could try any of the following:
To get the first element:
params[:result][:tracking_details][0][:status]
params[:result][:tracking_details].first[:status]
To get all the elements:
params[:result][:tracking_details].map{|x| x[:status]}