Step-by-Step Guide: Consuming CubeMaster API with Ruby on Rails (RestClient)
To use the CubeMaster API, you need an API key (TokenID) for authentication. Here's how to get started:
- Visit the CubeMaster website: https://cubemaster.net.
- Locate the "Sign In" option (typically found in the top-right corner).
- Fill out the registration form with your details (e.g., name, email, password, company information).
- After signing up, log in to your account dashboard.
- Navigate to the "Settings" - "Integration" section to generate your API key (TokenID).
- Generate an API key. Once generated, you’ll receive a unique
TokenID
(e.g.,abc123xyz789
). Copy this key and store it securely, as it will be used in the HTTP headers of your API requests. - Copy the TokenID and store it securely.
Note: The TokenID will be used in the HTTP headers of your POST request for authentication.
Tip: In Ruby on Rails, use the dotenv-rails
gem to manage environment variables. Add your TokenID to a .env
file:
CUBEMASTER_API_KEY=abc123xyz789
Then access it in your code with ENV['CUBEMASTER_API_KEY']
.
Ensure your Rails app is ready to make API calls using the RestClient
gem.
- Open your Rails project’s
Gemfile
and add: - Run
bundle install
in your terminal to install the gem. -
Create a new controller (e.g.,
LoadsController
) to handle API interactions:rails g controller Loads create
-
In
config/routes.rb
, add a route for the create action:post '/loads/create', to: 'loads#create'
- Verify your Rails app is running locally by executing
rails server
and visitinghttp://localhost:3000
.
gem 'rest-client'
UI Element: In your view (e.g., app/views/loads/new.html.erb
), add a simple form to trigger the API call:
<%= form_with url: "/loads/create", method: :post do |form| %>
<%= form.submit "Create Load", class: "btn btn-primary" %>
<% end %>
A RESTful API (Representational State Transfer) is a way for applications to communicate over the internet using standard HTTP methods like GET, POST, PUT, and DELETE. Here’s a beginner-friendly breakdown:
- Endpoint: A URL (e.g.,
https://api.cubemaster.net/loads
) where the API listens for requests. -
HTTP Methods:
GET
: Retrieve data.POST
: Send data to create something (like our load).
- Request: You send data (e.g., JSON) to the API.
- Response: The API sends back data (e.g., success message or error).
- Headers: Extra info sent with the request, like authentication tokens.
In this guide, we’ll use a POST
request to the /loads
endpoint to build a load, sending JSON data and receiving a JSON response.
Assume your customer’s legacy database stores order/shipment data (e.g., items, quantities, dimensions). Integrate this into your API request.
-
Create a model for your legacy data (e.g.,
Order
):rails g model Order name:string length:decimal width:decimal height:decimal weight:decimal qty:integer
- Migrate the database:
rails db:migrate
. -
Seed sample data in
db/seeds.rb
:
RunOrder.create(name: "ITEM001", length: 72, width: 30, height: 75, weight: 1002.45, qty: 16) Order.create(name: "ITEM002", length: 27.31, width: 37.5, height: 76.67, weight: 521.45, qty: 28)
rails db:seed
. -
In your controller, fetch this data to build the
Cargoes
array:orders = Order.all cargoes = orders.map do |order| { "Name": order.name, "Length": order.length, "Width": order.width, "Height": order.height, "Weight": order.weight, "Qty": order.qty, "OrientationsAllowed": "OrientationsAll", "TurnAllowedOnFloor": false, "ColorKnownName": "Brown" # Example default } end
This data will be merged into the API request payload in the next step.
Now, build the request payload and send it to the CubeMaster API using RestClient
.
In app/controllers/loads_controller.rb
:
require 'rest-client'
require 'json'
class LoadsController < ApplicationController
def create
# Fetch legacy data
orders = Order.all
cargoes = orders.map do |order|
{
"Name": order.name,
"Length": order.length,
"Width": order.width,
"Height": order.height,
"Weight": order.weight,
"Qty": order.qty,
"OrientationsAllowed": "OrientationsAll",
"TurnAllowedOnFloor": false,
"ColorKnownName": "Brown"
}
end
# Full payload
payload = {
"Title": "New Mixed Truck Load",
"Description": "Hello Web API",
"Cargoes": cargoes + [
{
"Name": "SKU0005",
"Length": 27.31,
"Width": 9.5,
"Height": 75.67,
"Weight": 501.45,
"OrientationsAllowed": "OrientationsAll",
"TurnAllowedOnFloor": true,
"Qty": 24,
"ColorKnownName": "Beige"
},
{ "Name": "SKU0005", "Qty": 23 },
{ "Name": "SKU0008", "Qty": 34 }
],
"Containers": [
{
"VehicleType": "Dry",
"Name": "53FT-Intermodal",
"Length": 630,
"Width": 98,
"Height": 106,
"ColorKnownName": "Blue"
}
],
"Rules": {
"IsWeightLimited": true,
"IsSequenceUsed": false,
"FillDirection": "FrontToRear",
"CalculationType": "MixLoad"
}
}.to_json
# Send POST request
response = RestClient.post(
'https://api.cubemaster.net/loads',
payload,
{
content_type: :json,
'TokenID': ENV['CUBEMASTER_API_KEY']
}
)
# Handle response (next step)
@result = JSON.parse(response.body)
render 'result'
rescue RestClient::ExceptionWithResponse => e
@error = e.response
render 'error'
end
end
Request JSON:
{
"Title": "New Mixed Truck Load",
"Description": "Hello Web API",
"Cargoes": [
{
"Name": "ITEM001",
"Length": 72,
"Width": 30,
"Height": 75,
"Weight": 1002.45,
"OrientationsAllowed": "OrientationsAll",
"TurnAllowedOnFloor": false,
"Qty": 16,
"ColorKnownName": "Brown"
},
{
"Name": "ITEM002",
"Length": 27.31,
"Width": 37.5,
"Height": 76.67,
"Weight": 521.45,
"OrientationsAllowed": "OrientationsAll",
"TurnAllowedOnFloor": false,
"Qty": 28,
"ColorKnownName": "Brown"
},
{
"Name": "SKU0005",
"Length": 27.31,
"Width": 9.5,
"Height": 75.67,
"Weight": 501.45,
"OrientationsAllowed": "OrientationsAll",
"TurnAllowedOnFloor": true,
"Qty": 24,
"ColorKnownName": "Beige"
},
{ "Name": "SKU0005", "Qty": 23 },
{ "Name": "SKU0008", "Qty": 34 }
],
"Containers": [
{
"VehicleType": "Dry",
"Name": "53FT-Intermodal",
"Length": 630,
"Width": 98,
"Height": 106,
"ColorKnownName": "Blue"
}
],
"Rules": {
"IsWeightLimited": true,
"IsSequenceUsed": false,
"FillDirection": "FrontToRear",
"CalculationType": "MixLoad"
}
}
UI Element: The form submission triggers this action. The TokenID
is passed in the headers for authentication.
After sending the request, process the response to display results or handle errors.
Create app/views/loads/result.html.erb
:
<h2>Load Creation Result</h2>
<p>Status: <%= @result["status"] %></p>
<p>Message: <%= @result["message"] %></p>
<% if @result["calculationError"].present? %>
<p class="text-danger">Error: <%= @result["calculationError"] %></p>
<% end %>
<h3>Load Summary</h3>
<ul>
<li>Cargoes Loaded: <%= @result["loadSummary"]["cargoesLoaded"] %></li>
<li>Volume Loaded: <%= @result["loadSummary"]["volumeLoaded"] %></li>
<li>Weight Loaded: <%= @result["loadSummary"]["weightLoaded"] %></li>
</ul>
<%= link_to "Back", new_load_path, class: "btn btn-secondary" %>
Create app/views/loads/error.html.erb
for errors:
<h2>Error Occurred</h2>
<p class="text-danger"><%= @error %></p>
<%= link_to "Try Again", new_load_path, class: "btn btn-secondary" %>
Response JSON:
{
"status": "succeed",
"message": "Engine created. 5 cargoes. 1 empty containers. Calculation started. Calculation ended. The load built successfully. The load saved to the cloud database.",
"calculationError": "InvalidCargoSize",
"document": {
"title": "New Mixed Truck Load",
"description": "Hello Web API",
"isShared": true,
"isAutoSaved": true,
"isPending": false,
"calculationTimeInSeconds": 0.6152743,
"processId": "",
"batchId": "",
"createdBy": "CHANG@LOGEN.CO.KR",
"createdAt": "2023-02-11T01:17:01.7392204+09:00",
"updatedAt": "0001-01-01T00:00:00"
},
"loadSummary": {
"cargoesLoaded": 68,
"piecesLoaded": 68,
"cargoesLeft": 0,
"piecesLeft": 57,
"unitloadsLoaded": 0,
"volumeLoaded": 5261723.4606,
"weightLoaded": 42674.59999999999,
"priceLoaded": 0,
"containersLoaded": 1
},
"filledContainers": [ /* Truncated for brevity */ ],
"manifest": [ /* Truncated for brevity */ ],
"reportLinks": {
"overview": "https://cubemaster.net/source/report/openlink.asp?id=cc3717aa-3460-4af0-ae59-6908bc0a496e"
},
"uom": "UnitEnglish"
}
Handling Details: Check status
for success, display loadSummary
metrics, and show calculationError
if present.
Ensure your API integration works smoothly by monitoring and debugging.
-
Logging: Add logging to your controller:
Check logs inRails.logger.info "Request sent: #{payload}" Rails.logger.info "Response received: #{response.body}"
log/development.log
. - Pry Debugging: Add
gem 'pry'
to your Gemfile, then insertbinding.pry
before theRestClient.post
call to inspect variables interactively. -
RestClient Debugging: Enable verbose output:
This prints request/response details to the console.RestClient.log = 'stdout'
- Test with Postman: Before coding, test the API in Postman with the same JSON and headers to verify behavior.
- Error Handling: Review the
rescue
block in Step 5 to catch and log API errors.
Tip: If you encounter issues like InvalidCargoSize
, double-check your Cargoes
data against API requirements.