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