class RailsAiAdmin::Presentation::CsvExport
The current list (search, list tab, filters and sort) as CSV, through the same grants as the pages: rows from the index relation and each record’s show grant, columns and values from its read grant.
Constants
- BATCH
- FORMULA
-
A spreadsheet runs a cell that starts with these as a formula (CSV injection); such cells get a leading apostrophe.
- NUMERIC
-
Number and time text is produced by coercion and cannot be a formula.
- Result
Public Class Methods
Source
# File lib/rails_ai_admin/presentation/csv_export.rb, line 17 def initialize(context, resource, limit: RailsAiAdmin.configuration.export_limit) @context, @resource, @limit = context, resource, limit @access = Authorization::Access.new(context, resource) end
Public Instance Methods
Source
# File lib/rails_ai_admin/presentation/csv_export.rb, line 22 def call(search: nil, sort: nil, direction: "asc", scope: nil, filters: nil) @access.authorize_export! relation = Queries::List.new(@context, @resource).relation(search: search, sort: sort, direction: direction, scope: scope, filters: filters) return Result.new(nil, 0, [], true) if relation.except(:order).limit(@limit + 1).count > @limit fields = @access.fields(:read, nil, view: :show) references = Fields::Association.new(@context, @resource) lines = [ line(fields.map(&:label)) ] # One query per list field and batch instead of one per row. lists = fields.select { |field| field.scalar_type == :references }.map(&:name) relation = relation.preload(*lists) if lists.any? rows = 0 offset = 0 loop do records = relation.offset(offset).limit(BATCH).to_a break if records.empty? offset += records.size fields.select { |field| field.scalar_type == :belongs_to }.each do |field| references.prime(field, records.filter_map { |record| record.has_attribute?(field.column) ? record.read_attribute(field.column)&.to_s : nil }) end records.each do |record| values = @access.project(record, view: :show) lines << line(fields.map { |field| values.key?(field.name.to_s) ? cell(field, values[field.name.to_s], references) : "" }) rows += 1 rescue AccessDenied # Left out like an unavailable row on the list page (RAA-001). next end break if records.size < BATCH || offset >= @limit end # The byte order mark lets spreadsheet programs read UTF-8. Result.new("#{lines.join}", rows, fields.map { |field| field.name.to_s }, false) end