LoginSignup
0
0

Ruby on RailsアプリでのSVGベースのOGP生成

Last updated at Posted at 2022-10-28

Controller&Viewのようなイメージで、SVGでテンプレートを用意して、OGP画像をレンダリングするライブラリを書いてみました。

使い方

  • app/ogps/***_ogp.rb OGP生成するコード (Mailerのようなイメージです)
  • app/views/opgs/***.svg.erb SVGテンプレート
app/ogps/question_ogp.rb
# frozen_string_literal: true

require Rails.root.join 'lib/ogp/base'

class QuestionOgp < Ogp::Base
  def render(question)
    @question = question
  end
end

  has_one_attached :ogp
  :
  question.update ogp: QuestionOgp.render(question.decorate)

コード

lib/ogp/base.rb
# frozen_string_literal: true

require 'tempfile'

module Ogp
  class Base
    class << self
      def views_path
        './app/views'
      end

      def template_prefix
        'ogps'
      end

      def template_name
        name.underscore.gsub(/_ogp$/, '')
      end

      def render(*parameters)
        svg_file = Tempfile.open(%w[ogp_ .svg])
        png_file = Tempfile.open(%w[ogp_ .png])
        begin
          svg_file.puts render_svg(*parameters)
          svg_file.close
          svg_file.open
          svg_to_png(svg_file, png_file)
          to_blob(png_file)
        ensure
          svg_file.close
          png_file.close
          svg_file.unlink
          png_file.unlink
        end
      end

      def to_blob(file)
        ActiveStorage::Blob.create_and_upload!(
          io: file,
          filename: 'ogp.png'
        ).signed_id
      end

      def render_svg(*parameters)
        instance = new
        instance.render(*parameters)
        action_view = Class.new(
          ActionView::Base.with_empty_template_cache
        ).with_view_paths(views_path, instance.assigns)
        action_view.render(template: template_name, prefixes: template_prefix, formats: [:svg])
      end

      def svg_to_png(svg_file, png_file)
        ImageProcessing::MiniMagick
          .source(svg_file)
          .convert('png')
          .call destination: png_file.path
      end
    end

    def assigns
      r = {}
      instance_variables.each do |name_sym|
        name_s = name_sym.to_s
        if name_s.start_with? '@'
          new_name_sym = name_s[1, name_s.size - 1].to_sym
          r[new_name_sym] = instance_variable_get(name_sym)
        end
      end
      r
    end
  end
end
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0