Search code examples
ruby-on-railsarraysrubyprawn

How to create arrays with different number of columns using a loop in Ruby?


I need to create arrays with different numbers of columns depending on whether certain variable values are "Show" or "Hide".

  • activity_types has many activities

  • activity_type belongs to a user

  • activities will have a number of columns: date, duration, cost, subject...

  • activity_types has a corresponding toggle column for each activity column, for example: subject_toggle, `duration_toggle

these toggle columns can have values of only "Show" or "Hide"

So I want to create a series of tables in prawnpdf for all the different activity_types. Each table should have different sets of columns shown depending on whether the activity_type toggle variable for that column is "show" or "hide"

I began working on this and quickly did not know how it conditionally creates columns in the array. I could leave it blank (have an if statement that would output blank if its "Hide") but it wouldn't remove the column.

Below is my code to create the tables for prawnpdf.

ActivityType.all.each do |type|
define_method("method_#{type.id}") do
  move_down 20
  font "Nunito"
  text type.title, :align => :left, size: 13, style: :bold
  move_down 5
  table eval("rows_#{type.id}"), :position => :center, :width => 540, :column_widths => {0 => 50, 8 => 60},
                                 :cell_style => {:font => "Nunito", :size => 10} do
    row(0).font_style = :bold
    columns(0..8).align = :center
    self.row_colors = ["F0F0F0", "FFFFFF"]
    self.header = true
  end
end end


  ActivityType.all.each do |type|
define_method("rows_#{type.id}") do
  [["Date", "Subject", "Details", "Time (min)","Contact","Detail","Outcome","Agent",""]] +
    type.activities.order(date: :asc).map do |activity|
      [activity.date.strftime("%b %d"), activity.subject, activity.contact, activity.detail,
      activity.outcome, activity.agent, activity.customer, activity.cost, activity.duration.to_i ]
    end
end end

Solution

  • You can use Array#compact to remove the empty elements from your array:

    https://ruby-doc.org/core-2.1.2/Array.html#method-i-compact

    compact → new_ary

    Returns a copy of self with all nil elements removed.

    [ "a", nil, "b", nil, "c", nil ].compact
                      #=> [ "a", "b", "c" ]
    

    However, it would only remove nil values. If your values can also be empty strings, you could use reject.

    In your particular case it would be:

    [activity.date.strftime("%b %d"), activity.subject, activity.contact, activity.detail,activity.outcome, activity.agent, activity.customer, activity.cost, activity.duration.to_i ].reject { |el| el.nil? || el.empty? }