rubypdf-generationprawn

Dynamic Header with prawn gem


I'm encountering an issue while rendering a header with the report_date argument passed into the render_header method. Despite passing a different report_date value each time, the PDF always displays the same date, which is not the expected behavior.

My expectation is that the PDF should render with the report_date value that's passed to the render_header method. However, it seems like the report_date argument isn't being utilized correctly within the method.

      def render_pages(pdf)
        grouped_items = rows.group_by { |item| item[0] }

        grouped_items.each_with_index do |(report_date, booking_items), index|
          render_page(pdf, report_date, booking_items)
          pdf.start_new_page unless index == grouped_items.size - 1
        end
      end

      # Renders a page of the PDF
      #
      # @param pdf [Prawn::Document] The PDF object
      def render_page(pdf, report_date, booking_items)
        pdf.repeat(:all, dynamic: true) do
          pdf.bounding_box([pdf.bounds.left, pdf.bounds.top], width: pdf.bounds.width) do
            render_header(pdf, report_date, organisation_name)
          end
          pdf.bounding_box([pdf.bounds.left, pdf.bounds.bottom + 150 ], width: pdf.bounds.width) do
            render_footer(pdf)
          end
        end
        render_body(pdf, report_date , booking_items)
      end

      def render_header(pdf, report_date, organisation_name)
        pdf.image open("https://s3.amazonaws.com/www-inside-design/uploads/2019/05/woolmarkimagelogo-1024x576.png"), width: 80, height: 80, position: :center
        pdf.text "HEY #{report_date}"
        pdf.table(
          [
            ["#{"Sumanth Samala PVT LTD"} - #{format_report_date(report_date)} \n Attendance Register", "Customer to complete all sections below \n Generated on #{Time.now.strftime("%d/%m/%Y %H:%M")}"]
          ],
          width: pdf.bounds.width,
          row_colors: ["808080"],
          cell_style: header_cell_style
        ) do |table|
          table.column(0).width = 464
        end
      end
    ```

Solution

  • Here is a stab in the dark but too long for a comment.

    We can render all the pages, while keeping track of the starting page and ending page for each report date.

    Then we can use repeat with those ranges to generate the header.

    def render_pages(pdf)
      grouped_items = rows.group_by(&:first)
    
      page_breaks = grouped_items.map.with_index(1) do |(report_date, booking_items), index|
        start_page = pdf.page_number
        render_page(pdf, report_date, booking_items)
        end_page = pdf.page_number 
        pdf.start_new_page unless index == grouped_items.size
        {pages: (start_page..end_page), report_date: report_date}
      end
      render_header_footer(pdf,page_breaks)
    end
    
    def render_page(pdf, report_date, booking_items)
      render_body(pdf, report_date , booking_items)
    end
    
    def render_header_footer(pdf,pages_headers)
      pages_headers.each do |page_data|
        pdf.repeat(page_data[:pages], dynamic: true) do
          pdf.bounding_box([pdf.bounds.left, pdf.bounds.top], width: pdf.bounds.width) do
            render_header(pdf, page_data[:report_date], organisation_name)
          end
          pdf.bounding_box([pdf.bounds.left, pdf.bounds.bottom + 150 ], width: pdf.bounds.width) do
            render_footer(pdf)
          end
        end
      end
    end 
    
    def render_header(pdf, report_date, organisation_name)
      pdf.image open("https://s3.amazonaws.com/www-inside-design/uploads/2019/05/woolmarkimagelogo-1024x576.png"), width: 80, height: 80, position: :center
      pdf.text "HEY #{report_date}"
      pdf.table(
        [
          ["#{"Sumanth Samala PVT LTD"} - #{format_report_date(report_date)} \n Attendance Register", "Customer to complete all sections below \n Generated on #{Time.now.strftime("%d/%m/%Y %H:%M")}"]
        ],
        width: pdf.bounds.width,
        row_colors: ["808080"],
        cell_style: header_cell_style
      ) do |table|
        table.column(0).width = 464
      end
    end