aldrien.h
aldrien.h

Reputation: 3635

How to render html tags correctly in PDF using gem "prawn"

I'm generating PDF report in my Rails app and uses gem "prawn" but having trouble handling the descriptions data because it contains html tags e.g. < b >, < ul >, < li >, < img >, < table > and more...

# frozen_string_literal: true
require 'prawn'
require 'prawn/table'

module User
  module Reports
    class GeneratePdf
      include ActionView::Helpers::NumberHelper
      include ActionView::Helpers::DateHelper
      include Seo::ApplicationHelper

      BORDER_COLOR = 'dddddd'.freeze
      TABLE_HEADER_COLOR = 'f2f0f0'.freeze
      WHITE_COLOR = 'ffffff'.freeze
      TABLE_HEADERS = [[I18n.t("seo.reports.type_of_fix"), I18n.t("seo.reports.description"), I18n.t("seo.reports.fixed_at")]].freeze
      A4_SIZE = [595.276, 841.890]

      attr_reader :shop

      def initialize(shop)
        @shop = shop
        @pdf = Prawn::Document.new(page_size: A4_SIZE)
        @document_width = @pdf.bounds.width
      end

      def perform
        report_summary_section
        reports_table
        @pdf.render
      end

      private

      def formatted_reports_data
        reports = Report.all
        reports.map do |report|
          fix_type = if report.issue_type.include?('_created')
            pretty_report_issue_type(report.issue_type, report.get_description_count)
          else
            pretty_report_issue_type(report.issue_type)
          end
          description = pretty_report_description(report.issue_type, report.description) # this is where the HTML tags came from
          fixed_at = "#{distance_of_time_in_words_to_now(report.fixed_at)} ago" if report.fixed_at
          [fix_type, description, fixed_at]
        end
      end

      def report_summary_section
        @pdf.text I18n.t("seo.dashboard.reports.title"), size: 16, style: :bold
        @pdf.move_down 5
        @pdf.text @shop.domain, size: 12, color: 'a6a6a6', inline_format: true
        @pdf.move_down 10

        summary_data = [
          [
            "#{I18n.t("seo.dashboard.reports.total_fixes")}\n<b>#{number_with_delimiter(@shop.reports_count) || 0}</b>",
            "#{I18n.t("seo.dashboard.reports.title_tags_fixed")}\n<b>#{number_with_delimiter(@shop.report_title_count) || 0}</b>",
            "#{I18n.t("seo.dashboard.reports.meta_tags_fixed")}\n<b>#{number_with_delimiter(@shop.report_desc_count) || 0}</b>"
          ],
          [
            "#{I18n.t("seo.dashboard.reports.alt_texts_fixed")}\n<b>#{number_with_delimiter(@shop.report_alt_count) || 0}</b>",
            "#{I18n.t("seo.dashboard.reports.links_fixed")}\n<b>#{number_with_delimiter(@shop.report_links_count) || 0}</b>",
            "#{I18n.t("seo.dashboard.reports.bulk_updates")}\n<b>#{number_with_delimiter(@shop.report_bulk_count) || 0}</b>"
          ]
        ]

        column_width = @document_width / 3.0

        summary_options = {
          cell_style: {
            size: 12,
            inline_format: true,
            padding: [15, 10],
            borders: [:top, :bottom, :left, :right],
            border_width: 1,
            border_color: BORDER_COLOR,
            align: :center,
            valign: :center
          },
          column_widths: [column_width] * 3
        }

        @pdf.table(summary_data, summary_options) do |table|
          table.cells.each do |cell|
            cell.content = cell.content.sub('<b>', '<font size="18"><b>').sub('</b>', '</b></font>')
          end
        end
      end

      def reports_table
        @pdf.move_down 20

        report_data_options = {
          width: @document_width,
          row_colors: [WHITE_COLOR],
          cell_style: {
            border_width: 1,
            borders: [:bottom],
            border_color: BORDER_COLOR,
            size: 10,
            inline_format: true
          }
        }

        @pdf.table(TABLE_HEADERS + formatted_reports_data, report_data_options) do |table|
          table.row(0).font_style = :bold
          table.row(0).background_color = TABLE_HEADER_COLOR
          table.row(0).size = 9

          table.cells.each do |cell|
            cell.content = cell.content # I plan to catch here, i can sanitize but I need to render the <html> codes as it is in PDF
          end
        end
      end

    end
  end
end

Upvotes: 0

Views: 54

Answers (0)

Related Questions