Immagini OG in Ruby on Rails
Genera immagini OG in Ruby on Rails con l'API dinamica a pagamento di FastOG — con un abbonamento all'API dinamica (crea la tua chiave API nel dashboard). Anteprima nel tester gratuito di immagini OG, poi genera immagini Open Graph dinamiche dalla tua app Rails con URL firmati HMAC.
Avvio rapido
1. Creare il servizio firmatario
# app/services/fastog_signer.rb
class QuickogSigner
def self.generate_signed_og_url(params, options = {})
base_url = options[:base_url] || ENV.fetch("FASTOG_BASE_URL", "https://fastog.com/api/v1/og")
api_key = options[:api_key] || ENV.fetch("FASTOG_API_KEY")
hmac_secret = options[:hmac_secret] || ENV.fetch("FASTOG_HMAC_SECRET")
raise "Missing FASTOG_API_KEY or FASTOG_HMAC_SECRET" unless api_key && hmac_secret
all = params.merge(key: api_key)
pairs = all.flat_map do |k, v|
Array(v).sort.map { |vv| "#{enc(k)}=#{enc(vv)}" }
end
canonical = pairs.sort.join("&")
signature = OpenSSL::HMAC.hexdigest("SHA256", hmac_secret, "GET/api/v1/og\n#{canonical}")
"#{base_url}?#{URI.encode_www_form(all.merge(s: signature))}"
end
def self.enc(s)
s.to_s.gsub(/[^A-Za-z0-9\-._~]/) { |c| c.bytes.map { |b| "%%%02X" % b }.join }
end
private_class_method :enc
end
Perché un enc personalizzato? Codifica in percentuale con esadecimali maiuscoli, lasciando solo i caratteri non riservati -._~ — quindi gli spazi diventano %20, mai +, in linea con il rawurlencode del server. Se usi CGI.escape o URI.encode_www_form_component, entrambi generano + per gli spazi: normalizza prima con .gsub('+', '%20').
2. Configurazione
# config/application.rb
config.fastog = ActiveSupport::OrderedOptions.new
config.fastog.api_key = ENV.fetch("FASTOG_API_KEY", nil)
config.fastog.hmac_secret = ENV.fetch("FASTOG_HMAC_SECRET", nil)
config.fastog.base_url = ENV.fetch("FASTOG_BASE_URL", "https://fastog.com/api/v1/og")
# .env
FASTOG_API_KEY=sk_your_full_api_key_here
FASTOG_HMAC_SECRET=your_64_char_hex_secret_here
Controller
# app/controllers/blog_controller.rb
class BlogController < ApplicationController
def show
@post = Post.find_by!(slug: params[:slug])
@og_image_url = QuickogSigner.generate_signed_og_url(
template: "blog",
title: @post.title,
subtitle: @post.excerpt,
author: @post.author.name
)
end
end
Vista
<!-- app/views/blog/show.html.erb -->
<% content_for :head do %>
<meta property="og:image" content="<%= @og_image_url %>" />
<meta property="og:title" content="<%= @post.title %>" />
<meta property="og:description" content="<%= @post.excerpt %>" />
<% end %>
<article>
<h1><%= @post.title %></h1>
<p><%= @post.excerpt %></p>
</article>
Layout
<!-- app/views/layouts/application.html.erb -->
<head>
<%= yield :head %>
</head>
Helper
# app/helpers/fastog_helper.rb
module QuickogHelper
def og_image_url(template:, **params)
QuickogSigner.generate_signed_og_url({ template: template }.merge(params))
end
end
<!-- In view -->
<meta property="og:image" content="<%= og_image_url(template: 'blog', title: @post.title) %>" />
Esempio di e-commerce
# app/controllers/products_controller.rb
class ProductsController < ApplicationController
def show
@product = Product.find(params[:id])
@og_image_url = QuickogSigner.generate_signed_og_url(
template: "ecommerce",
title: @product.name,
price: @product.formatted_price,
image: @product.image_url
)
end
end
Esempio di Post del Blog
# app/controllers/users_controller.rb
class UsersController < ApplicationController
def show
@user = User.find_by!(username: params[:username])
@og_image_url = QuickogSigner.generate_signed_og_url(
template: "blog",
title: @user.name,
subtitle: @user.bio,
author: @user.name
)
end
end
Endpoint API
# config/routes.rb
get "api/og", to: "api/og#generate"
# app/controllers/api/og_controller.rb
module Api
class OgController < ApplicationController
skip_before_action :verify_authenticity_token
def generate
title = params[:title]
template = params[:template] || "default"
unless title
return render json: { error: "Missing title" }, status: :bad_request
end
og_image_url = QuickogSigner.generate_signed_og_url(
template: template,
title: title
)
render json: { ogImageUrl: og_image_url }
end
end
end
Turbo/Hotwire
<!-- app/views/blog/_post.html.erb -->
<%= turbo_frame_tag "post_#{@post.id}" do %>
<meta property="og:image" content="<%= og_image_url(template: 'blog', title: @post.title) %>" />
<h2><%= link_to @post.title, blog_path(@post) %></h2>
<% end %>
Errori Comuni
Firmare il Messaggio Sbagliato
❌ Errato: "GET/api/v1/og#{canonical}" — manca il separatore di nuova riga.
✅ Corretto: "GET/api/v1/og\n#{canonical}" — metodo + percorso, una nuova riga, poi la query canonica.
Lasciare key Fuori dalla Firma
❌ Errato: firmare solo i tuoi parametri di contenuto e aggiungere key all'URL successivamente.
✅ Corretto: key viene unito ai parametri prima che la query canonica venga costruita e appare nell'URL finale.
401 missing_signature / invalid_signature
missing_signature (401) significa che key o s manca dall'URL. invalid_signature (401) significa che la query canonica non corrisponde — verifica la nuova riga nel messaggio firmato, lo stesso hmac_secret su entrambi i lati e che enc codifichi gli spazi come %20 (mai +).
Esporre il Segreto HMAC
Non esporre mai FASTOG_HMAC_SECRET in JavaScript frontend o codice lato client.