OG Images trong Ruby on Rails
Tạo OG images trong Ruby on Rails với Dynamic API dựa trên đăng ký của FastOG — với gói đăng ký Dynamic API (tạo API key của bạn trong dashboard). Xem trước trong Free OG Image Tester, sau đó hiển thị các Open Graph images động từ ứng dụng Rails của bạn với các URL được ký bằng HMAC.
Bắt đầu nhanh
1. Tạo dịch vụ ký (signer service)
# 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
Vì sao cần enc tùy chỉnh? Nó mã hóa phần trăm (percent-encode) với chữ hoa thập lục phân, chỉ để lại các ký tự không dành riêng -._~ — vì vậy khoảng trắng trở thành %20, không bao giờ là +, khớp với rawurlencode của máy chủ. Nếu bạn thay bằng CGI.escape hoặc URI.encode_www_form_component, cả hai đều tạo ra + cho khoảng trắng: hãy chuẩn hóa bằng .gsub('+', '%20') trước.
2. Cấu hình
# 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
Bộ điều khiển (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
Chế độ xem
<!-- 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>
Bố cục
<!-- app/views/layouts/application.html.erb -->
<head>
<%= yield :head %>
</head>
Trợ giúp
# 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) %>" />
Ví dụ về Thương mại điện tử
# 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
Ví dụ Bài Viết 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
Điểm cuối 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 %>
Các Lỗi Thường Gặp
Ký Sai Nội Dung
❌ Sai: "GET/api/v1/og#{canonical}" — thiếu dấu phân cách dòng mới.
✅ Đúng: "GET/api/v1/og\n#{canonical}" — phương thức + đường dẫn, một dòng mới, sau đó là chuỗi truy vấn chuẩn hóa.
Bỏ Sót key Trong Chữ Ký
❌ Sai: chỉ ký các tham số nội dung của bạn và thêm key vào URL sau đó.
✅ Đúng: key được hợp nhất vào các tham số trước khi chuỗi truy vấn chuẩn hóa được xây dựng và xuất hiện trong URL cuối cùng.
Lỗi 401 missing_signature / invalid_signature
missing_signature (401) nghĩa là key hoặc s bị thiếu trong URL. invalid_signature (401) nghĩa là chuỗi chuẩn hóa không khớp — hãy kiểm tra dòng mới trong thông điệp đã ký, cùng một hmac_secret ở cả hai phía và đảm bảo enc mã hóa phần trăm khoảng trắng thành %20 (không bao giờ +).
Lộ Bí Mật HMAC
Không bao giờ để lộ FASTOG_HMAC_SECRET trong JavaScript phía frontend hoặc mã phía máy khách.