Module: Exportable

Extended by:
ActiveSupport::Concern
Included in:
Importo::BaseImporter
Defined in:
app/importers/concerns/exportable.rb

Instance Method Summary collapse

Instance Method Details

#export(data_rows) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'app/importers/concerns/exportable.rb', line 58

def export(data_rows)
  xls = Axlsx::Package.new
  xls.use_shared_strings = true
  workbook = xls.workbook
  sheet = workbook.add_worksheet(name: friendly_name&.pluralize || model.name.demodulize.pluralize)
  workbook.styles do |style|
    introduction_style = style.add_style(bg_color: "E2EEDA")
    header_style = style.add_style(b: true, bg_color: "A8D08E", border: {style: :thin, color: "000000"})
    header_required_style = style.add_style(b: true, bg_color: "A8D08E", fg_color: "C00100", border: {style: :thin, color: "000000"})

    # Introduction
    introduction.each_with_index do |intro, i|
      text = intro.is_a?(Symbol) ? I18n.t(intro, scope: [:importers, self.class.name.underscore.to_s, :introduction]) : intro
      sheet.add_row [text], style: [introduction_style] * export_columns.count
      sheet.merge_cells "A#{i + 1}:#{nr_to_col(export_columns.count - 1)}#{i + 1}"
    end

    # Header row
    sheet.add_row export_columns.values.map(&:name), style: export_columns.map { |_, c| c.options[:required] ? header_required_style : header_style }

    export_columns.each.with_index do |f, i|
      field = f.last
      sheet.add_comment ref: "#{nr_to_col(i)}#{introduction.count + 1}", author: "", text: field.hint, visible: false if field.hint.present?
    end
    styles = export_columns.map do |_, c|
      if c.options.dig(:export, :format) == "number" || (c.options.dig(:export, :format).nil? && c.options.dig(:export, :example).is_a?(Numeric))
        number = workbook.styles.add_style format_code: "#"
      elsif c.options.dig(:export, :format) == "text" || (c.options.dig(:export, :format).nil? && c.options.dig(:export, :example).is_a?(String))
        text = workbook.styles.add_style format_code: "@"
      elsif c.options.dig(:export, :format)
        workbook.styles.add_style format_code: c.options.dig(:export, :format).to_s
      else
        workbook.styles.add_style format_code: "General"
      end
    end
    # Examples
    data_rows.each do |data|
      sheet.add_row data, style: styles
    end
  end

  sheet.column_info[0].width = 10

  sheet = workbook.add_worksheet(name: I18n.t("importo.sheet.explanation.name"))

  workbook.styles do |style|
    introduction_style = style.add_style(bg_color: "E2EEDA")
    header_style = style.add_style(b: true, bg_color: "A8D08E", border: {style: :thin, color: "000000"})

    column_style = style.add_style(b: true)
    required_style = style.add_style(b: true, fg_color: "C00100")
    wrap_style = workbook.styles.add_style alignment: {wrap_text: true}

    # Introduction
    introduction.each_with_index do |intro, i|
      text = intro.is_a?(Symbol) ? I18n.t(intro, scope: [:importers, self.class.name.underscore.to_s, :introduction]) : intro
      sheet.add_row [text], style: [introduction_style] * 2
      sheet.merge_cells "A#{i + 1}:B#{i + 1}"
    end

    # Header row
    sheet.add_row [I18n.t("importo.sheet.explanation.column"), I18n.t("importo.sheet.explanation.value"), I18n.t("importo.sheet.explanation.explanation"), I18n.t("importo.sheet.explanation.example")], style: [header_style] * 4
    export_columns.each do |_, c|
      styles = [c.options[:required] ? required_style : column_style, wrap_style]
      sheet.add_row [c.name, c.value, c.explanation, c.example], style: styles
    end
  end

  sheet.column_info[0].width = 40
  sheet.column_info[1].width = 150

  xls.to_stream
end

#export_columnsObject



132
133
134
# File 'app/importers/concerns/exportable.rb', line 132

def export_columns
  @export_columns ||= columns.reject { |_, column| column.options[:hidden] }
end

#export_dataObject



28
29
30
# File 'app/importers/concerns/exportable.rb', line 28

def export_data
  export_scope.map { |record| export_row(record) }
end

#export_fileObject

Generates an export based on the attributes and scope.



24
25
26
# File 'app/importers/concerns/exportable.rb', line 24

def export_file
  export(export_data)
end

#export_row(record) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'app/importers/concerns/exportable.rb', line 40

def export_row(record)
  export_columns.map do |_, c|
    value = ""

    if c.options[:attribute]
      if c.options[:export]&.key?(:value)
        value = c.options[:export][:value].call(record) if c.options[:export][:value].is_a?(Proc)
      elsif record.respond_to?(c.options[:attribute])
        value = record.send(c.options[:attribute])
        value = value&.body&.to_html if value.is_a?(ActionText::RichText)
      end
      value ||= record.attributes[c.options[:attribute].to_s] if value.nil?
    end

    value
  end
end

#export_scopeObject



32
33
34
35
36
37
38
# File 'app/importers/concerns/exportable.rb', line 32

def export_scope
  if self.class.allow_export?
    model.all
  else
    model.none
  end
end

#sample_dataObject



15
16
17
18
19
# File 'app/importers/concerns/exportable.rb', line 15

def sample_data
  sample_data = []
  100.times { sample_data << export_columns.map { |_, c| c.options[:example] || "" } }
  sample_data
end

#sample_fileObject

Generates a sample excel file as a stream



11
12
13
# File 'app/importers/concerns/exportable.rb', line 11

def sample_file
  export(sample_data)
end