Ruby on Rails 中的 OG 圖片
使用 FastOG 的訂閱制動態 API(Dynamic API)在 Ruby on Rails 中產生 OG 圖片——訂閱動態 API 後(請在儀表板中建立您的 API 金鑰)。先在免費的 OG 圖片測試工具(Free OG Image Tester)中預覽,再透過 HMAC 簽署的 URL 從您的 Rails 應用程式渲染動態的 Open Graph 圖片。
快速開始
1. 建立簽署者服務
# 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
為什麼需要自訂 enc? 它會以大寫十六進位進行百分號編碼,只保留 -._~ 中的非保留字元——因此空格會變成 %20,絕不會是 +,與伺服器的 rawurlencode 相符。若改用 CGI.escape 或 URI.encode_www_form_component,兩者都會將空格輸出為 +:請先以 .gsub('+', '%20') 進行正規化。
2. 設定
# 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
控制器
# 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
檢視
<!-- 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>
版面配置
<!-- app/views/layouts/application.html.erb -->
<head>
<%= yield :head %>
</head>
輔助工具
# 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) %>" />
電子商務範例
# 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
部落格文章範例
# 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
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 %>
常見陷阱
簽署錯誤的訊息
❌ 錯誤:"GET/api/v1/og#{canonical}" — 缺少換行分隔符號。
✅ 正確:"GET/api/v1/og\n#{canonical}" — 方法 + 路徑、一個換行,然後是正規化查詢字串。
將 key 遺漏於簽章之外
❌ 錯誤:只簽署你的內容參數,事後再將 key 附加到 URL 上。
✅ 正確:key 會在建立正規化查詢字串之前合併進參數中,並出現在最終的 URL 裡。
401 missing_signature / invalid_signature
missing_signature(401)表示 URL 中缺少 key 或 s。invalid_signature(401)表示正規化內容不符 — 請確認簽署訊息中的換行、兩端使用相同的 hmac_secret,以及 enc 將空格以 %20 進行百分號編碼(絕非 +)。
暴露 HMAC 密鑰
切勿在前端 JavaScript 或客戶端程式碼中暴露 FASTOG_HMAC_SECRET。