Skip to content

Commit 10c3e1f

Browse files
committed
Merge pull request #64 from ifyouseewendy/feature/add_batch_transaction_option
Feature/add batch transaction option
2 parents ca7d286 + c2d9ed8 commit 10c3e1f

File tree

7 files changed

+46
-9
lines changed

7 files changed

+46
-9
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ Tool | Description
6565
:csv_options |hash with column separator, row separator, etc
6666
:validate |bool means perform validations or not
6767
:batch_size |integer value of max record count inserted by 1 query/transaction
68+
:batch_transaction |bool (false by default), if transaction is used when batch importing and works when :validate is set to true
6869
:before_import |proc for before import action, hook called with importer object
6970
:after_import |proc for after import action, hook called with importer object
7071
:before_batch_import |proc for before each batch action, called with importer object

lib/active_admin_import/dsl.rb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ module DSL
88
# +back+:: resource action to redirect after processing
99
# +csv_options+:: hash to override default CSV options
1010
# +batch_size+:: integer value of max record count inserted by 1 query/transaction
11+
# +batch_transaction+:: bool (false by default), if transaction is used when batch importing and works when :validate is set to true
1112
# +before_import+:: proc for before import action, hook called with importer object
1213
# +after_import+:: proc for after import action, hook called with importer object
1314
# +before_batch_import+:: proc for before each batch action, called with importer object
@@ -31,11 +32,12 @@ module DSL
3132
if result.empty?
3233
flash[:warning] = I18n.t('active_admin_import.file_empty_error')
3334
else
34-
if result.has_imported?
35-
flash[:notice] = I18n.t('active_admin_import.imported', count: result.imported_qty, model: model_name, plural_model: plural_model_name)
36-
end
3735
if result.has_failed?
3836
flash[:error] = I18n.t('active_admin_import.failed', count: result.failed.count, model: model_name, plural_model: plural_model_name)
37+
return if options[:batch_transaction]
38+
end
39+
if result.has_imported?
40+
flash[:notice] = I18n.t('active_admin_import.imported', count: result.imported_qty, model: model_name, plural_model: plural_model_name)
3941
end
4042
end
4143
end

lib/active_admin_import/importer.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class Importer
1616
:after_batch_import,
1717
:headers_rewrites,
1818
:batch_size,
19+
:batch_transaction,
1920
:csv_options
2021
].freeze
2122

@@ -47,7 +48,7 @@ def import
4748
end
4849

4950
def import_options
50-
@import_options ||= options.slice(:validate, :on_duplicate_key_update, :ignore, :timestamps)
51+
@import_options ||= options.slice(:validate, :on_duplicate_key_update, :ignore, :timestamps, :batch_transaction)
5152
end
5253

5354
def batch_replace(header_key, options)
@@ -97,12 +98,14 @@ def run_callback(name)
9798
end
9899

99100
def batch_import
101+
batch_result = nil
100102
@resource.transaction do
101103
run_callback(:before_batch_import)
102104
batch_result = resource.import(headers.values, csv_lines, import_options)
105+
raise ActiveRecord::Rollback if import_options[:batch_transaction] && batch_result.failed_instances.any?
103106
run_callback(:after_batch_import)
104-
batch_result
105107
end
108+
batch_result
106109
end
107110

108111
def assign_options(options)

lib/active_admin_import/options.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module Options
66
:csv_options,
77
:validate,
88
:batch_size,
9+
:batch_transaction,
910
:before_import,
1011
:after_import,
1112
:before_batch_import,
@@ -40,4 +41,4 @@ def self.options_for(config, options= {})
4041
end
4142

4243
end
43-
end
44+
end
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Name,Last name,Birthday
2+
Jim,Doe,1986-05-01
3+
Jane,Roe,1986-05-01

spec/import_spec.rb

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,14 +292,41 @@ def upload_file!(name, ext='csv')
292292
end
293293
end
294294

295-
context "with invalid data insert" do
295+
context "with invalid data insert on DB constraint" do
296+
# :name field has an uniq index
296297
it "should render error" do
297298
upload_file!(:authors_invalid_db)
298299
expect(page).to have_content "Error:"
299300
expect(Author.count).to eq(0)
300301
end
301302
end
302303

304+
context "with invalid data insert on model validation" do
305+
let(:options) { { validate: true } }
306+
307+
before do
308+
Author.create!(name: "John", last_name: "Doe")
309+
end
310+
311+
it "should render both successful and failed message" do
312+
upload_file!(:authors_invalid_model)
313+
expect(page).to have_content "Failed to import 1 author"
314+
expect(page).to have_content "Successfully imported 1 author"
315+
expect(Author.count).to eq(2)
316+
end
317+
318+
context "use batch_transaction to make transaction work on model validation" do
319+
let(:options) { { validate: true, batch_transaction: true } }
320+
321+
it "should render only the failed message" do
322+
upload_file!(:authors_invalid_model)
323+
expect(page).to have_content "Failed to import 1 author"
324+
expect(page).to_not have_content "Successfully imported"
325+
expect(Author.count).to eq(1)
326+
end
327+
end
328+
end
329+
303330
context "with invalid records" do
304331
context "with validation" do
305332
it "should render error" do
@@ -402,4 +429,4 @@ def upload_file!(name, ext='csv')
402429

403430
end
404431

405-
end
432+
end

spec/support/rails_template.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
generate :model, 'post title:string:uniq body:text author:references'
55

66
#Add validation
7-
inject_into_file "app/models/author.rb", " validates_presence_of :name\n", after: "Base\n"
7+
inject_into_file "app/models/author.rb", " validates_presence_of :name\n validates_uniqueness_of :last_name\n", after: "Base\n"
88
inject_into_file "app/models/post.rb", " validates_presence_of :author\n", after: ":author\n"
99

1010
# Configure default_url_options in test environment

0 commit comments

Comments
 (0)