Problems with generating page headers in ruport

34 views
Skip to first unread message

Fafnir

unread,
Sep 23, 2010, 4:29:12 PM9/23/10
to Ruby Reports
Howdy,

I have been digging around for days and havent seen anything on the
problem im encountering, so was wondering if someone else had
encountered it.

I am trying to place a page header on multiple pages using the
all_pages extension in ruport

However I cant seem to get anything to respect the top_margin.

I am using the example directly from the ruportbook (ruportbook.com/
printable_documents.html) under the section for generating page
headers. Below is the code, if someone could give me a push in the
right direction that would be great.

The error I get with the below code is being told that top_margin is
not a valid method.

class ReportPDF < Ruport::Formatter::PDF
renders :pdf, :for => [ MemberTableController,
MemberPrintViewController]
build :member_report do
pdf_writer.top_margin = 30
build_member_report_header

draw_table(data[0],
:column_options => {
:width => 90,
:heading => { :justification => :center},
"City/State/Zip\nDischarge Date" => {:justification
=> :left, :width => 180}
})
build_member_report_footer
render_pdf

end

Andrew France

unread,
Sep 23, 2010, 4:41:26 PM9/23/10
to ruby-r...@googlegroups.com
On 23/09/10 21:29, Fafnir wrote:
> I am trying to place a page header on multiple pages using the
> all_pages extension in ruport

I've never heard of all_pages before, it seems you're using a gem called
pdf-helpers but we don't even have the source on the GitHub account! I
will have a look at that and get it uploaded if it looks useful.


> However I cant seem to get anything to respect the top_margin.
>
> I am using the example directly from the ruportbook (ruportbook.com/
> printable_documents.html) under the section for generating page
> headers. Below is the code, if someone could give me a push in the
> right direction that would be great.
>
> The error I get with the below code is being told that top_margin is
> not a valid method.
>
> class ReportPDF< Ruport::Formatter::PDF
> renders :pdf, :for => [ MemberTableController,
> MemberPrintViewController]
> build :member_report do
> pdf_writer.top_margin = 30

A quick search of the API docs shows neither PDF::Writer or the Ruport
PDF formatter implement a top_margin method so I guess the book is out
of date. You can use PDF::Writer's own margins_pt method or if I don't
see why move_down wouldn't work.

Hope that helps,
Andrew

Fafnir Crow

unread,
Sep 23, 2010, 4:55:07 PM9/23/10
to ruby-r...@googlegroups.com
I only came across pdf-helpers because it was in the book. Would never
have known it otherwise

> A quick search of the API docs shows neither PDF::Writer or the Ruport PDF
> formatter implement a top_margin method so I guess the book is out of date.
> You can use PDF::Writer's own margins_pt method or if I don't see why
> move_down wouldn't work.


I have also tried margins_pt but it does not actually have any effect
on the resulting PDF. move_down also gives me a 'undefined method'
error. These things point me to that im probably calling them wrong,
but im not sure what...

inside PDF::simpleTable there is also a :header_gap attribute, which
claims to leave header space with each new page, however even when
forcing its value straight in initialize, did it ever seem to have any
effect whatsoever.


Fafnir Crow

Andrew France

unread,
Sep 23, 2010, 5:09:01 PM9/23/10
to ruby-r...@googlegroups.com
On 23/09/10 21:55, Fafnir Crow wrote:
>> A quick search of the API docs shows neither PDF::Writer or the Ruport PDF
>> formatter implement a top_margin method so I guess the book is out of date.
>> You can use PDF::Writer's own margins_pt method or if I don't see why
>> move_down wouldn't work.
>
> I have also tried margins_pt but it does not actually have any effect
> on the resulting PDF. move_down also gives me a 'undefined method'
> error. These things point me to that im probably calling them wrong,
> but im not sure what...

margins_pt only works before any content is written (maybe per-page, not
sure).

move_down is implemented in the formatter so don't prepend pdf_writer,
it's simply:
def move_down(n)
pdf_writer.y -= n
end

> inside PDF::simpleTable there is also a :header_gap attribute, which
> claims to leave header space with each new page, however even when
> forcing its value straight in initialize, did it ever seem to have any
> effect whatsoever.

At a guess that value is probably only ready by SimpleTable.

Regards,
Andrew

Fafnir Crow

unread,
Sep 23, 2010, 6:08:42 PM9/23/10
to ruby-r...@googlegroups.com
> margins_pt only works before any content is written (maybe per-page, not
> sure).

I can understand the margins only working before being written, but im
not really sure how what im doing is not happening then. Here is some
more depth to maybe help. I dont know if im missing something basic in
either ruby or ruport...

So when the user clicks to download a member report, the function
generates the data for basic_member_report to be passed as below. (in
the app controller)

pdf = MemberTableController.render_pdf(:data => [basic_member_report],
:title_str => title_str,
:paper_orientation => :landscape,
:search_str => search_str,
:post_num => current_user.organization.post_number,
:post_name => current_user.organization.name,
:count => basic_member_report.size)

Which my understanding passes control to the helper code below
(because this class extends the ruport controller for that call ?)

class MemberTableController < Ruport::Controller

stage :member_report
required_option :post_num, :count
end

This is where my understanding is a bit murky, and a bit of guesswork
is whats driving this, but control is then passed (by the stage
command? cant find references to it) to the code before, listed as
follows:

class ReportPDF < Ruport::Formatter::PDF
renders :pdf, :for => [ MemberTableController,
MemberPrintViewController]

build :member_report do
build_member_report_header

draw_table(data[0],
:column_options => {
:width => 90,
:heading => { :justification => :center},
"City/State/Zip\nDischarge Date" => {:justification =>
:left, :width => 180}
})
build_member_report_footer
render_pdf

end

I figured the control passing here mainly by inference (when I add
silly phrases here, they add on my pdf) but figure im in the right
direction :)

the first build command (build :member_report) i dont understand, but
assume its a control block piece.

so in all the above, im not really clear on when PDF::Writer.new gets
called in teh control scheme, so I can figure out how to set the
margins there.

Maybe im missing something else basic?

By the way, thank you very much for your quick and helpful response. I
have banged my head on the wall for days digging into things trying to
learn rather than come in to a email group with a 'how do I do this
basic thing, because i cant be bothered to dig through the
documentation' and i appreciate trying to help me understand whats
going on here.

Fafnir

Andrew France

unread,
Sep 23, 2010, 7:11:24 PM9/23/10
to ruby-r...@googlegroups.com
On 23/09/10 23:08, Fafnir Crow wrote:
>
> So when the user clicks to download a member report, the function
> generates the data for basic_member_report to be passed as below. (in
> the app controller)
>
> pdf = MemberTableController.render_pdf(:data => [basic_member_report],
> :title_str => title_str,
> :paper_orientation => :landscape,
> :search_str => search_str,
> :post_num => current_user.organization.post_number,
> :post_name => current_user.organization.name,
> :count => basic_member_report.size)
>
> Which my understanding passes control to the helper code below
> (because this class extends the ruport controller for that call ?)

Yes render_pdf is a dynamic method on Ruport::Controller that your
controller inherits.


> class MemberTableController< Ruport::Controller
>
> stage :member_report
> required_option :post_num, :count
> end
>
> This is where my understanding is a bit murky, and a bit of guesswork
> is whats driving this, but control is then passed (by the stage
> command? cant find references to it) to the code before, listed as
> follows:

When you call render the controller runs each build method in the
formatter with the same name as the stage in the order the stages are
listed. Formatters don't have to implement all the stages though.


> class ReportPDF< Ruport::Formatter::PDF
> renders :pdf, :for => [ MemberTableController,
> MemberPrintViewController]
>
> build :member_report do
> build_member_report_header
>
> draw_table(data[0],
> :column_options => {
> :width => 90,
> :heading => { :justification => :center},
> "City/State/Zip\nDischarge Date" => {:justification =>
> :left, :width => 180}
> })
> build_member_report_footer
> render_pdf
>
> end

> the first build command (build :member_report) i dont understand, but


> assume its a control block piece.

build :member_report creates a method called build_member_report, which
is then called by the controller because of the stage of the same name.
It's just a syntactical nicety.
Ideally you would do:
stage :header, :body, :footer, :finalize
Where :header = build_member_report_header, :body = :member_report etc:
build :header do ... end
build :body do ... end ...

> so in all the above, im not really clear on when PDF::Writer.new gets
> called in teh control scheme, so I can figure out how to set the
> margins there.

The instantiation of PDF::Writer is fixed in the formatter, but it only
takes size and orientation options anyway according to API doc
(http://ruby-pdf.rubyforge.org/pdf-writer/doc/index.html). I looked at
the margins_pt docs and it goes to some length to update the cursor
position when you change them.

The draw_table command uses PDF::Writer's SimpleTable, maybe it is
ignoring margins. Try temporarily replacing the table with text and see
if that obeys the margins. You can also set
pdf_writer.absolute_top_boundary, or set pdf_writer.y explicitly.

Hope that helps!
Andrew

Fafnir Crow

unread,
Oct 11, 2010, 1:06:18 PM10/11/10
to ruby-r...@googlegroups.com
After a long delay of dealing with other things, I have gotten client
approval on my project that it worked to their satisfaction, so I
wanted to make sure that I listed how I fixed things here, so that
others might find some workarounds a bit easier.

First the all_pages function from pdf-helpers-0.1.0 was a great help.
It was located at http://gems.rubyreports.org/gems/ (which kind of
amused me when I went back to find it and you had mentioned you hadnt
heard of it andrew :) )

It does have the limitation however of doing it on Every page. Which
means that you will not be able to put two different 'headers' on
seperate pages of the report. For the PDF that had two reports in it,
I simply forced the titles to match and moved on.

The second limitation is that the all_pages function is not directly
aware of what page you are on when it is going in and generating the
headers. so I used pdf_writer.start_page_numbering to manually number
all the pages. An interesting quirk about start page numbering, is you
can stop and start it multiple times, so your page numbering can
potentially match multiple reports in the same output PDF.

There is a slight issue with draw_table (not in the ruport side, but
rather in the pdf writer side) that will cause it to ignore the header
gap on the first page of the table, so you must manually add a margin
to that page before you begin the table, otherwise it will overlap
your header.

I think that covers all the problems I ran into, and how I solved
them. Hope it helps others in the future!

Fafnir Crow

> --
> You received this message because you are subscribed to the Google Groups
> "Ruby Reports" group.
> To post to this group, send email to ruby-r...@googlegroups.com.
> To unsubscribe from this group, send email to
> ruby-reports...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/ruby-reports?hl=en.
>
>

Reply all
Reply to author
Forward
0 new messages