Skip to content

Commit df5ed39

Browse files
authored
Merge pull request #214 from activeadmin-plugins/custom-import-result
Allow custom ImportResult subclass via :result_class option
2 parents ce38f01 + 4d356b4 commit df5ed39

File tree

5 files changed

+79
-3
lines changed

5 files changed

+79
-3
lines changed

README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ Tool | Description
6868
:timestamps |bool, tells activerecord-import to not add timestamps (if false) even if record timestamps is disabled in ActiveRecord::Base
6969
:template |custom template rendering
7070
:template_object |object passing to view
71+
:result_class |custom `ImportResult` subclass to collect data from each batch (e.g. inserted ids). Must respond to `add(batch_result, qty)` plus the readers used in flash messages (`failed`, `total`, `imported_qty`, `imported?`, `failed?`, `empty?`, `failed_message`).
7172
:resource_class |resource class name
7273
:resource_label |resource label value
7374
:plural_resource_label |pluralized resource label value (default config.plural_resource_label)
@@ -77,6 +78,37 @@ Tool | Description
7778

7879

7980

81+
#### Custom ImportResult
82+
83+
To collect extra data from each batch (for example the ids of inserted rows so you can enqueue background jobs against them), pass a subclass of `ActiveAdminImport::ImportResult` via `:result_class`:
84+
85+
```ruby
86+
class ImportResultWithIds < ActiveAdminImport::ImportResult
87+
attr_reader :ids
88+
89+
def initialize
90+
super
91+
@ids = []
92+
end
93+
94+
def add(batch_result, qty)
95+
super
96+
@ids.concat(Array(batch_result.ids))
97+
end
98+
end
99+
100+
ActiveAdmin.register Author do
101+
active_admin_import result_class: ImportResultWithIds do |result, options|
102+
EnqueueAuthorsJob.perform_later(result.ids) if result.imported?
103+
instance_exec(result, options, &ActiveAdminImport::DSL::DEFAULT_RESULT_PROC)
104+
end
105+
end
106+
```
107+
108+
The action block is invoked via `instance_exec` with `result` and `options` as block arguments, so you can either capture them with `do |result, options|` or read them as locals when no arguments are declared.
109+
110+
Note: which batch-result attributes are populated depends on the database adapter and the import options. `activerecord-import` returns ids reliably on PostgreSQL; on MySQL/SQLite the behavior depends on the adapter and options like `on_duplicate_key_update`. Putting the collection logic in your own subclass keeps these adapter quirks in your application code.
111+
80112
#### Wiki
81113

82114
[Check various examples](https://github.com/activeadmin-plugins/active_admin_import/wiki)

lib/active_admin_import/dsl.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def active_admin_import(options = {}, &block)
104104
result = @importer.import
105105

106106
if block_given?
107-
instance_eval(&block)
107+
instance_exec result, options, &block
108108
else
109109
instance_exec result, options, &DEFAULT_RESULT_PROC
110110
end

lib/active_admin_import/importer.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ class Importer
1818
:headers_rewrites,
1919
:batch_size,
2020
:batch_transaction,
21-
:csv_options
21+
:csv_options,
22+
:result_class
2223
].freeze
2324

2425
def initialize(resource, model, options)
@@ -29,7 +30,7 @@ def initialize(resource, model, options)
2930
end
3031

3132
def import_result
32-
@import_result ||= ImportResult.new
33+
@import_result ||= (options[:result_class] || ImportResult).new
3334
end
3435

3536
def file

lib/active_admin_import/options.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ module Options
1616
:ignore,
1717
:template,
1818
:template_object,
19+
:result_class,
1920
:resource_class,
2021
:resource_label,
2122
:plural_resource_label,

spec/import_spec.rb

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,4 +689,46 @@ def active_admin_import_context
689689
end
690690
end
691691
end
692+
693+
# PG-only: activerecord-import populates `result.ids` reliably on PostgreSQL
694+
# via RETURNING. On MySQL/SQLite the array is not populated by default, so
695+
# the assertion would not be meaningful there. The :result_class option
696+
# itself works on every adapter — this spec just demonstrates the canonical
697+
# PR #191 use case (collecting inserted ids) on the adapter that supports it.
698+
if ENV['DB'] == 'postgres'
699+
context 'with custom result_class (PostgreSQL)' do
700+
# Subclass that captures inserted ids alongside the standard counters.
701+
# Lives in user-land so the gem itself stays free of adapter-specific
702+
# quirks around RETURNING. This is the example documented in the README.
703+
class ImportResultWithIds < ActiveAdminImport::ImportResult
704+
attr_reader :ids
705+
706+
def initialize
707+
super
708+
@ids = []
709+
end
710+
711+
def add(batch_result, qty)
712+
super
713+
@ids.concat(Array(batch_result.ids))
714+
end
715+
end
716+
717+
before do
718+
add_author_resource(result_class: ImportResultWithIds) do |result, _options|
719+
# Expose the captured ids on the flash so the test asserts via the
720+
# rendered page rather than closure capture.
721+
flash[:notice] = "Imported ids: [#{result.ids.sort.join(',')}]"
722+
end
723+
visit '/admin/authors/import'
724+
upload_file!(:authors)
725+
end
726+
727+
it 'collects the ids of inserted records via the custom subclass' do
728+
expect(Author.count).to eq(2)
729+
expected = "Imported ids: [#{Author.pluck(:id).sort.join(',')}]"
730+
expect(page).to have_content(expected)
731+
end
732+
end
733+
end
692734
end

0 commit comments

Comments
 (0)