الموضوع

صور OG في Ruby on Rails

قم بإنشاء صور OG في Ruby on Rails باستخدام واجهة برمجة التطبيقات الديناميكية (Dynamic API) القائمة على الاشتراك من FastOG — مع اشتراك واجهة برمجة التطبيقات الديناميكية (أنشئ مفتاح API الخاص بك في لوحة التحكم). يمكنك المعاينة في أداة اختبار صور OG المجانية، ثم عرض صور Open Graph الديناميكية من تطبيق Rails الخاص بك باستخدام عناوين URL موقعة بـ HMAC.

بدء الاستخدام السريع

1. إنشاء خدمة التوقيع

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

لماذا خدمة توقيع مخصصة enc؟ لأنها تقوم بترميز النسبة المئوية بأحرف سداسية عشرية كبيرة، مع إبقاء -._~ فقط غير محجوز — لذا تتحول المسافات إلى %20، وليس + أبدًا، بما يتوافق مع rawurlencode الخاص بالخادم. إذا استبدلتها بـ CGI.escape أو URI.encode_www_form_component، فكلاهما يُنتج + للمسافات: قم بالتطبيع باستخدام .gsub('+', '%20') أولًا.

2. الإعداد

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

العرض

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>

التخطيط

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

المساعد

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

مثال التجارة الإلكترونية

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

مثال على منشور مدونة

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

نقطة نهاية 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 %>

الأخطاء الشائعة

توقيع الرسالة الخاطئة

❌ خطأ: "GET/api/v1/og#{canonical}" — فقدان فاصل السطر الجديد. ✅ صحيح: "GET/api/v1/og\n#{canonical}" — الطريقة + المسار، ثم سطر جديد، ثم الاستعلام الأساسي (canonical query).

استبعاد key من التوقيع

❌ خطأ: توقيع معاملات المحتوى فقط وإلحاق key بعنوان URL لاحقًا. ✅ صحيح: يتم دمج key في المعاملات قبل بناء الاستعلام الأساسي، ويظهر في عنوان URL النهائي.

401 missing_signature / invalid_signature

missing_signature (401) تعني أن key أو s مفقود من عنوان URL. invalid_signature (401) تعني أن الاستعلام الأساسي لم يتطابق — تحقق من وجود سطر جديد في الرسالة الموقعة، ومن استخدام نفس hmac_secret على كلا الجانبين، ومن أن enc يقوم بترميز المسافات كنسبة مئوية كـ %20 (وليس + أبدًا).

كشف سر HMAC

لا تكشف أبدًا عن FASTOG_HMAC_SECRET في JavaScript الخاص بالواجهة الأمامية أو في أي كود يعمل على جانب العميل.

مرجع API الكامل

جرّبه مجانًا — لا حاجة للتسجيل

معاينة واختبار صور OG الديناميكية في ثوانٍ.

افتح أداة اختبار OG المجانية

A BeCaSimulations site