FastOG
Topik

Gambar OG di Ruby on Rails

Buat gambar OG di Ruby on Rails menggunakan API Dinamis berbasis langganan dari FastOG — dengan langganan API Dinamis (buat kunci API Anda di dasbor). Pratinjau di Penguji Gambar OG Gratis, lalu render gambar Open Graph dinamis dari aplikasi Rails Anda dengan URL yang ditandatangani HMAC.

Mulai Cepat

1. Buat layanan penanda tangan

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

Mengapa enc khusus? Ia melakukan penyandian persen dengan heksadesimal huruf besar, hanya menyisakan -._~ yang tidak dicadangkan — sehingga spasi menjadi %20, bukan +, sesuai dengan rawurlencode server. Jika Anda menggantinya dengan CGI.escape atau URI.encode_www_form_component, keduanya menghasilkan + untuk spasi: normalisasi dengan .gsub('+', '%20') terlebih dahulu.

2. Konfigurasi

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

Tampilan

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>

Tata Letak

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) %>" />

Contoh 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

Contoh Posting 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

Titik Akhir 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 %>

Kesalahan Umum

Menandatangani Pesan yang Salah

❌ Salah: "GET/api/v1/og#{canonical}" — melewatkan pemisah baris baru. ✅ Benar: "GET/api/v1/og\n#{canonical}" — metode + jalur, baris baru, lalu query kanonik.

Mengabaikan key dari Tanda Tangan

❌ Salah: menandatangani hanya parameter konten Anda dan menambahkan key ke URL setelahnya. ✅ Benar: key digabungkan ke dalam parameter sebelum query kanonik dibuat, dan muncul di URL akhir.

401 missing_signature / invalid_signature

missing_signature (401) berarti key atau s tidak ada di URL. invalid_signature (401) berarti kanonik tidak cocok — pastikan baris baru dalam pesan yang ditandatangani, hmac_secret yang sama di kedua sisi, dan bahwa enc melakukan percent-encode spasi sebagai %20 (bukan +).

Membocorkan Rahasia HMAC

Jangan pernah mengekspos FASTOG_HMAC_SECRET dalam JavaScript frontend atau kode sisi klien.

Referensi API Lengkap

Coba gratis — tanpa perlu mendaftar

Pratinjau dan uji gambar OG dinamis dalam hitungan detik.

Buka Penguji Gambar OG Gratis

A BeCaSimulations site