I'm using Prawn to generate a PDF document but getting the above error when trying to generate tables for items. Any idea on how to go about this?
app/models/storage_request.rb
class StorageRequest < ActiveRecord::Base
  has_many :packages
  accepts_nested_attributes_for :packages, :allow_destroy => true
  attr_accessible :user_id, :state, :packages_attributes
end
app/models/package.rb
class Package < ActiveRecord::Base
  belongs_to :storage_request
  has_many :items
  accepts_nested_attributes_for :items, allow_destroy: true
  attr_accessible :user_id, :state, :items_attributes
end
app/models/item.rb
class Item < ActiveRecord::Base
  belongs_to :package
  attr_accessible :name, :user_id
end
app/pdfs/storage_request_pdf.rb
class StorageRequestPdf < Prawn::Document
  def initialize(storage_request, view)
    super(top_margin: 50)
    @storage_request = storage_request
    @view = view
    list_items
  end
  def list_items
    move_down 20
    text "Summary", size: 30, style: :bold, align: :center
    table item_rows do
      row(0).font_style = :bold
      self.row_colors = ["DDDDDD", "FFFFFF"]
      self.header = true
    end
  end
  def item_rows
    @storage_request.packages.map do |package|
      package.items.map do |item|
        ([["ID", "Item Name"]] +
        [item.id, item.name])
      end
    end
  end
end
                Your item_rows method returns a malformed array. It prepends the header to every row and returns an array like this:
[ [["ID", "Item Name"], 1, "Foo"],
  [["ID", "Item Name"], 2, "Bar"],
  [["ID", "Item Name"], 3, "Baz"] ]
whereas Prawn expects an array like this:
[ ["ID", "Item Name"],
  [1, "Foo"],
  [2, "Bar"],
  [3, "Baz"] ]
You should always write tests for your code to catch such errors early on.
I would define rows and header in separate methods:
def item_header
  ["ID", "Item Name"]
end
def item_rows
  @storage_request.packages.map do |package|
    package.items.map { |item| [item.id, item.name] }
  end
end
def item_table_data
  [item_header, *item_rows] 
end
And create the table with:
table(item_table_data) do
  # ...
end
The item_rows method still is a bit ugly because it reaches deep into the objects. I would add a has_many :through association to StorageRequest:
class StorageRequest < ActiveRecord::Base
  has_many :packages
  has_many :items, :through => :packages
And refactor the item_rows method:
def item_rows
  @storage_request.items { |item| [item.id, item.name] }
end
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With