lib/active_admin/csv_builder.rb in activeadmin-0.6.6 vs lib/active_admin/csv_builder.rb in activeadmin-1.0.0.pre1
- old
+ new
@@ -4,46 +4,123 @@
# Usage example:
#
# csv_builder = CSVBuilder.new
# csv_builder.column :id
# csv_builder.column("Name") { |resource| resource.full_name }
+ # csv_builder.column(:name, humanize: false)
+ # csv_builder.column("name", humanize: false) { |resource| resource.full_name }
#
- # csv_builder = CSVBuilder.new :col_sep => ";"
+ # csv_builder = CSVBuilder.new col_sep: ";"
+ # csv_builder = CSVBuilder.new humanize_name: false
# csv_builder.column :id
#
#
class CSVBuilder
# Return a default CSVBuilder for a resource
# The CSVBuilder's columns would be Id followed by this
# resource's content columns
def self.default_for_resource(resource)
- new.tap do |csv_builder|
- csv_builder.column(:id)
- resource.content_columns.each do |content_column|
- csv_builder.column(content_column.name.to_sym)
- end
+ new resource: resource do
+ column :id
+ resource.content_columns.each { |c| column c.name.to_sym }
end
end
- attr_reader :columns, :options
+ attr_reader :columns, :options, :view_context
+ COLUMN_TRANSITIVE_OPTIONS = [:humanize_name].freeze
+
def initialize(options={}, &block)
- @columns, @options = [], options
- instance_eval &block if block_given?
+ @resource = options.delete(:resource)
+ @columns, @options, @block = [], options, block
end
- # Add a column
- def column(name, &block)
- @columns << Column.new(name, block)
+ def column(name, options={}, &block)
+ @columns << Column.new(name, @resource, column_transitive_options.merge(options), block)
end
+ def build(controller, receiver)
+ @collection = controller.send(:find_collection, except: :pagination)
+ options = ActiveAdmin.application.csv_options.merge self.options
+ columns = exec_columns controller.view_context
+
+ if byte_order_mark = options.delete(:byte_order_mark)
+ receiver << byte_order_mark
+ end
+
+ if options.delete(:column_names) { true }
+ receiver << CSV.generate_line(columns.map{ |c| encode c.name, options }, options)
+ end
+
+ (1..paginated_collection.total_pages).each do |page_no|
+ paginated_collection(page_no).each do |resource|
+ resource = controller.send :apply_decorator, resource
+ receiver << CSV.generate_line(build_row(resource, columns, options), options)
+ end
+ end
+ end
+
+ def exec_columns(view_context = nil)
+ @view_context = view_context
+ @columns = [] # we want to re-render these every instance
+ instance_exec &@block if @block.present?
+ columns
+ end
+
+ def build_row(resource, columns, options)
+ columns.map do |column|
+ encode call_method_or_proc_on(resource, column.data), options
+ end
+ end
+
+ def encode(content, options)
+ if options[:encoding]
+ content.to_s.encode options[:encoding], options[:encoding_options]
+ else
+ content
+ end
+ end
+
+ def method_missing(method, *args, &block)
+ if @view_context.respond_to? method
+ @view_context.public_send method, *args, &block
+ else
+ super
+ end
+ end
+
class Column
- attr_reader :name, :data
+ attr_reader :name, :data, :options
- def initialize(name, block = nil)
- @name = name.is_a?(Symbol) ? name.to_s.titleize : name
+ DEFAULT_OPTIONS = { humanize_name: true }
+
+ def initialize(name, resource = nil, options = {}, block = nil)
+ @options = options.reverse_merge(DEFAULT_OPTIONS)
+ @name = humanize_name(name, resource, @options[:humanize_name])
@data = block || name.to_sym
end
+
+ def humanize_name(name, resource, humanize_name_option)
+ if humanize_name_option
+ name.is_a?(Symbol) && resource.present? ? resource.human_attribute_name(name) : name.to_s.humanize
+ else
+ name.to_s
+ end
+ end
+ end
+
+ private
+
+ def column_transitive_options
+ @column_transitive_options ||= @options.slice(*COLUMN_TRANSITIVE_OPTIONS)
+ end
+
+ def paginated_collection(page_no = 1)
+ @collection.public_send(Kaminari.config.page_method_name, page_no).per(batch_size)
+ end
+
+ def batch_size
+ 1000
end
end
end