Argomento

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

ruby
# 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

ruby
# 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")
bash
# .env
FASTOG_API_KEY=sk_your_full_api_key_here
FASTOG_HMAC_SECRET=your_64_char_hex_secret_here

Controller

ruby
# 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

erb
<!-- 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

erb
<!-- app/views/layouts/application.html.erb -->
<head>
  <%= yield :head %>
</head>

Helper

ruby
# app/helpers/fastog_helper.rb
module QuickogHelper
  def og_image_url(template:, **params)
    QuickogSigner.generate_signed_og_url({ template: template }.merge(params))
  end
end
erb
<!-- In view -->
<meta property="og:image" content="<%= og_image_url(template: 'blog', title: @post.title) %>" />

Esempio di e-commerce

ruby
# 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

ruby
# 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

ruby
# config/routes.rb
get "api/og", to: "api/og#generate"
ruby
# 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

erb
<!-- 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.

Riferimento API completo

Provalo gratis — nessuna registrazione richiesta

Anteprima e test delle immagini OG dinamiche in pochi secondi.

Apri il tester gratuito di immagini OG

A BeCaSimulations site