Search code examples
ruby-on-railsprawnheroku-postgres

getting a "undefined local variable or method error" for generating prawn pdf only on heroku server not locally


Whenever I enter a new record in the database it is not recognised by prawn until I restart my Heroku server. I have no problems locally (using Cloud9) however when using heroku I get an error like:

NameError (undefined local variable or method `method_199'"

where method_199 is not found because I just added it to the database. If I re-deploy my code to heroku then it will recognise method_199.

This seems to be an issue only with my prawn pdf. On the heroku site the rest of the database seems to update and respond just fine (meaning I can make an update and it shows up without having to re-deploy the app)

pdf.rb

class ReportTwoPdf < Prawn::Document
 def initialize(property, current_user, start_date, end_date)
 super(top_margin: 50)

@property = property
@current_user = current_user
@start_date = start_date
@end_date = end_date

# @activity_types.each do |type|
# eval("test_#{type.id}")
# end


current_user.activity_types.each do |type|
  if @property.activities.where(activity_type_id: type.id).where(:date => 
  (@start_date..@end_date)).count > 0
    eval("method_#{type.id}")
  else
  end
end

end

ActivityType.all.each do |type|
define_method("method_#{type.id}") do
  move_down 20
  a = [1,
       type.subject_toggle == "Show" ? 1 : nil,
       type.contact_toggle == "Show" ? 1 : nil,
       type.agent_toggle == "Show" ? 1 : nil,
       type.customer_toggle == "Show" ? 1 : nil,
       type.detail_toggle == "Show" ? 1 : nil,
       type.outcome_toggle == "Show" ? 1 : nil,
       type.cost_toggle == "Show" ? 1 : nil,
       type.duration_toggle == "Show" ? 1 : nil].compact.length - 1

  font "Nunito"
  text type.title, :align => :left, size: 12, style: :bold
  move_down 5
  table eval("row_#{type.id}"), :position => :center, :width => 540, 
:column_widths => {0 => 50,1 => @min_width, a => 60},
                        :cell_style => {:font => "Nunito", :size => 9} do
    row(0).font_style = :bold
    columns(0..8).align = :center
    self.row_colors = ["F0F0F0", "FFFFFF"]
    self.header = true
  end
end
end

Controller:

 def create_pdf
@property = Property.find(params.fetch("id_to_display"))
@current_user = current_user
@start_date = Date.strptime(params.fetch("start_date"), "%Y-%m-%d")
@end_date = Date.strptime(params.fetch("end_date"), "%Y-%m-%d")
@user = current_user

respond_to do |format|
  format.html
  format.pdf do
    pdf = ReportTwoPdf.new(@property, @current_user, @start_date, @end_date)
    send_data pdf.render, :filename => "Report: #{@property.address}.pdf", :type => "application/pdf", disposition: "inline"
  end
end
end

GemFile

gem "prawn"
gem 'prawn-table'

Solution

  • This behaviour is expected, because in production classes are evaluated only once at server startup. This in turn normally happens only on deploy or scaling. Your data in ActivityType obviously can change more often than you deploy

    I do not see why you need to define these dynamic methods, you can handle ActivityTypes as you do any other data:

    class ReportTwoPdf < Prawn::Document
      def initialize(property, current_user, start_date, end_date)
        super(top_margin: 50)
    
        @property = property
        @current_user = current_user
        @start_date = start_date
        @end_date = end_date
    
    
        current_user.activity_types.each do |type|
          if @property.activities.where(activity_type_id: type.id).where(date: (@start_date..@end_date)).count > 0
            handle_activity_type(type)
          else
          end
        end
    
      end
    
      def some_row_similar(type)
        # here goes the code
      end
    
      def handle_activity_type(type)
        move_down 20
        a = [
          type.subject_toggle,
          type.contact_toggle,
          type.agent_toggle,
          type.customer_toggle,
          type.detail_toggle,
          type.outcome_toggle,
          type.cost_toggle,
          type.duration_toggle
        ].count{|toggle| toggle == "Show" }
    
        font "Nunito"
        text type.title, align: :left, size: 12, style: :bold
        move_down 5
    
        table some_row_similar(type), position: :center, width: 540, 
            column_widths: {0 => 50, 1 => @min_width, a => 60},
            cell_style: {font: "Nunito", size: 9} do
          row(0).font_style = :bold
          columns(0..8).align = :center
          self.row_colors = ["F0F0F0", "FFFFFF"]
          self.header = true
        end
      end
    
    end