Ruby Quickstart
Server-side: tile proxy, geocoding. For client-side maps, embed MapLibre JS in your views.
Gemfile
ruby
gem 'http' # or use Net::HTTP from stdlibTile proxy (Rails)
ruby
# config/routes.rb
get '/tiles/:z/:x/:y.pbf', to: 'tiles#show', constraints: { z: /\d+/, x: /\d+/, y: /\d+/ }
# app/controllers/tiles_controller.rb
require 'openssl'
require 'http'
class TilesController < ApplicationController
KEY = ENV.fetch('MFD_SRV_KEY')
SECRET = ENV.fetch('MFD_SRV_SECRET')
def show
z, x, y = params.values_at(:z, :x, :y)
path = "/tiles/#{z}/#{x}/#{y}.pbf"
ts = Time.now.to_i.to_s
sig = OpenSSL::HMAC.hexdigest('SHA256', SECRET, "GET\n#{path}\n#{ts}")
upstream = HTTP.headers(
'Authorization' => "Bearer #{KEY}",
'X-MFD-Timestamp' => ts,
'X-MFD-Signature' => sig
).get("https://tiles.mapsfordevs.com#{path}")
response.headers['Cache-Control'] = 'public, max-age=86400'
send_data upstream.body.to_s,
type: 'application/x-protobuf',
status: upstream.status,
disposition: 'inline'
end
endGeocoding service
ruby
require 'http'
require 'json'
class MapsForDevs
BASE = 'https://api.mapsfordevs.com'
def initialize(api_key)
@api_key = api_key
end
def geocode(query, country: nil, limit: 5)
params = { q: query, limit: limit }
params[:country] = country if country
resp = HTTP.headers(authorization: "Bearer #{@api_key}")
.get("#{BASE}/geocode/forward", params: params)
body = JSON.parse(resp.body.to_s, symbolize_names: true)
raise body[:error] unless body[:ok]
body[:items]
end
def reverse(lat, lng)
resp = HTTP.headers(authorization: "Bearer #{@api_key}")
.get("#{BASE}/geocode/reverse", params: { lat: lat, lng: lng, limit: 1 })
body = JSON.parse(resp.body.to_s, symbolize_names: true)
raise body[:error] unless body[:ok]
body[:items].first
end
end
mfd = MapsForDevs.new(ENV['MFD_PUB_KEY'])
mfd.geocode('80 Sturdee Ave Rosebank', country: 'za').each do |hit|
puts "#{hit[:lat]}, #{hit[:lng]} — #{hit[:label]}"
endRetry with backoff
ruby
def fetch_with_retry(req, attempts: 4)
attempts.times do |i|
resp = req.call
return resp if resp.status < 500 && resp.status != 429
delay = (resp.headers['Retry-After'] || (2**i)).to_i
sleep delay
end
raise 'failed after retries'
end