active_admin_import 7.0.0 → 8.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +37 -3
  3. data/lib/active_admin_import/importer.rb +23 -20
  4. data/lib/active_admin_import/version.rb +1 -1
  5. metadata +3 -39
  6. data/.github/workflows/test.yml +0 -211
  7. data/.gitignore +0 -19
  8. data/.rubocop.yml +0 -43
  9. data/Gemfile +0 -37
  10. data/Rakefile +0 -5
  11. data/active_admin_import.gemspec +0 -22
  12. data/spec/fixtures/files/author.csv +0 -2
  13. data/spec/fixtures/files/author_broken_header.csv +0 -2
  14. data/spec/fixtures/files/author_invalid.csv +0 -2
  15. data/spec/fixtures/files/author_invalid_format.txt +0 -2
  16. data/spec/fixtures/files/authors.csv +0 -3
  17. data/spec/fixtures/files/authors_bom.csv +0 -3
  18. data/spec/fixtures/files/authors_invalid_db.csv +0 -3
  19. data/spec/fixtures/files/authors_invalid_model.csv +0 -3
  20. data/spec/fixtures/files/authors_no_headers.csv +0 -2
  21. data/spec/fixtures/files/authors_values_exceeded_headers.csv +0 -3
  22. data/spec/fixtures/files/authors_win1251_win_endline.csv +0 -3
  23. data/spec/fixtures/files/authors_with_ids.csv +0 -3
  24. data/spec/fixtures/files/authors_with_semicolons.csv +0 -3
  25. data/spec/fixtures/files/authors_with_tabs.tsv +0 -3
  26. data/spec/fixtures/files/empty.csv +0 -0
  27. data/spec/fixtures/files/only_headers.csv +0 -1
  28. data/spec/fixtures/files/post_comments.csv +0 -3
  29. data/spec/fixtures/files/posts.csv +0 -4
  30. data/spec/fixtures/files/posts_for_author.csv +0 -3
  31. data/spec/fixtures/files/posts_for_author_no_headers.csv +0 -2
  32. data/spec/import_result_spec.rb +0 -39
  33. data/spec/import_spec.rb +0 -734
  34. data/spec/model_spec.rb +0 -6
  35. data/spec/spec_helper.rb +0 -54
  36. data/spec/support/active_model_lint.rb +0 -15
  37. data/spec/support/admin.rb +0 -32
  38. data/spec/support/import_form_selectors.rb +0 -24
  39. data/spec/support/rails_template.rb +0 -71
  40. data/spec/support/test_app_paths.rb +0 -14
  41. data/tasks/test.rake +0 -30
data/spec/import_spec.rb DELETED
@@ -1,734 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'spec_helper'
3
-
4
- describe 'import', type: :feature do
5
- shared_examples 'successful inserts' do |encoding, csv_file_name|
6
- let(:options) do
7
- attributes = { force_encoding: encoding }
8
- { template_object: ActiveAdminImport::Model.new(attributes) }
9
- end
10
-
11
- before do
12
- upload_file!(csv_file_name)
13
- end
14
-
15
- it 'should import file with many records' do
16
- expect(page).to have_content 'Successfully imported 2 authors'
17
- expect(Author.count).to eq(2)
18
- Author.all.each do |author|
19
- expect(author).to be_valid
20
- expect(author.name).to be_present
21
- expect(author.last_name).to be_present
22
- end
23
- end
24
- end
25
-
26
- def with_zipped_csv(name, &block)
27
- zip_file = File.expand_path("./spec/fixtures/files/#{name}.zip")
28
-
29
- begin
30
- Zip::File.open(zip_file, create: true) do |z|
31
- z.add "#{name}.csv", File.expand_path("./spec/fixtures/files/#{name}.csv")
32
- end
33
- instance_eval &block
34
- ensure
35
- begin
36
- File.delete zip_file
37
- rescue
38
- nil
39
- end
40
- end
41
- end
42
-
43
- def upload_file!(name, ext = 'csv')
44
- attach_file(ImportFormSelectors.file_input_id, File.expand_path("./spec/fixtures/files/#{name}.#{ext}"))
45
- find_button(ImportFormSelectors.import_button_text).click
46
- end
47
-
48
- context 'posts index' do
49
- before do
50
- Author.create!(name: 'John', last_name: 'Doe')
51
- Author.create!(name: 'Jane', last_name: 'Roe')
52
- end
53
-
54
- context 'for csv for particular author' do
55
- let(:author) { Author.take }
56
-
57
- shared_examples 'successful inserts for author' do
58
- it 'should use predefined author_id' do
59
- expect(Post.where(author_id: author.id).count).to eq(Post.count)
60
- end
61
-
62
- it 'should be imported' do
63
- expect(Post.count).to eq(2)
64
- expect(page).to have_content 'Successfully imported 2 posts'
65
- end
66
- end
67
-
68
- context 'no headers' do
69
- before do
70
- add_post_resource(template_object: ActiveAdminImport::Model.new(author_id: author.id,
71
- csv_headers: [:title, :body, :author_id]),
72
- validate: true,
73
- before_batch_import: lambda do |importer|
74
- importer.csv_lines.map! { |row| row << importer.model.author_id }
75
- end
76
- )
77
-
78
- visit '/admin/posts/import'
79
- upload_file!(:posts_for_author_no_headers)
80
- end
81
- include_examples 'successful inserts for author'
82
- end
83
-
84
- context 'with headers' do
85
- before do
86
- add_post_resource(template_object: ActiveAdminImport::Model.new(author_id: author.id),
87
- validate: true,
88
- before_batch_import: lambda do |importer|
89
- importer.csv_lines.map! { |row| row << importer.model.author_id }
90
- importer.headers.merge!(:'Author Id' => :author_id)
91
- end
92
- )
93
-
94
- visit '/admin/posts/import'
95
- upload_file!(:posts_for_author)
96
- end
97
- include_examples 'successful inserts for author'
98
- end
99
-
100
- context 'when template object passed like proc' do
101
- before do
102
- add_post_resource(template_object: -> { ActiveAdminImport::Model.new(author_id: author.id) },
103
- validate: true,
104
- before_batch_import: lambda do |importer|
105
- importer.csv_lines.map! { |row| row << importer.model.author_id }
106
- importer.headers.merge!(:'Author Id' => :author_id)
107
- end
108
- )
109
-
110
- visit '/admin/posts/import'
111
- upload_file!(:posts_for_author)
112
- end
113
-
114
- include_examples 'successful inserts for author'
115
-
116
- context 'after successful import try without file' do
117
- let(:after_successful_import_do!) do
118
- # reload page
119
- visit '/admin/posts/import'
120
- # submit form without file
121
- find_button(ImportFormSelectors.import_button_text).click
122
- end
123
-
124
- it 'should render validation error' do
125
- after_successful_import_do!
126
-
127
- expect(page).to have_content I18n.t('active_admin_import.no_file_error')
128
- end
129
- end
130
- end
131
- end
132
-
133
- context 'for csv with author name' do
134
- before do
135
- add_post_resource(
136
- validate: true,
137
- template_object: ActiveAdminImport::Model.new,
138
- headers_rewrites: { :'Author Name' => :author_id },
139
- before_batch_import: lambda do |importer|
140
- authors_names = importer.values_at(:author_id)
141
- # replacing author name with author id
142
- authors = Author.where(name: authors_names).pluck(:name, :id)
143
- # {"Jane" => 2, "John" => 1}
144
- options = Hash[*authors.flatten]
145
- importer.batch_replace(:author_id, options)
146
- end
147
- )
148
- visit '/admin/posts/import'
149
- upload_file!(:posts)
150
- end
151
-
152
- it 'should resolve author_id by author name' do
153
- Post.all.each do |post|
154
- expect(Author.where(id: post.author.id)).to be_present
155
- end
156
- end
157
-
158
- it 'should be imported' do
159
- expect(Post.count).to eq(2)
160
- expect(page).to have_content 'Successfully imported 2 posts'
161
- end
162
- end
163
- end
164
-
165
- context 'authors index' do
166
- before do
167
- add_author_resource
168
- end
169
-
170
- it 'should navigate to import page' do
171
- # TODO: removing this causes undefined method `ransack' for #<ActiveRecord::Relation []>
172
- allow_any_instance_of(Admin::AuthorsController).to receive(:find_collection).and_return(Author.all)
173
- visit '/admin/authors'
174
- find_link(ImportFormSelectors.import_link_text).click
175
- expect(current_path).to eq('/admin/authors/import')
176
- end
177
- end
178
-
179
- context 'with custom block' do
180
- before do
181
- add_author_resource({}) do
182
- flash[:notice] = 'some custom message'
183
- end
184
- visit '/admin/authors/import'
185
- end
186
-
187
- it 'should display notice from custom block' do
188
- upload_file!(:author)
189
- expect(page).to have_content 'some custom message'
190
- end
191
- end
192
-
193
- context 'authors already exist' do
194
- before do
195
- Author.create!(id: 1, name: 'Jane', last_name: 'Roe')
196
- Author.create!(id: 2, name: 'John', last_name: 'Doe')
197
- end
198
-
199
- context 'having authors with the same Id' do
200
- before do
201
- add_author_resource(
202
- before_batch_import: lambda do |importer|
203
- Author.where(id: importer.values_at('id')).delete_all
204
- end
205
- )
206
- visit '/admin/authors/import'
207
- upload_file!(:authors_with_ids)
208
- end
209
-
210
- it 'should replace authors' do
211
- expect(page).to have_content 'Successfully imported 2 authors'
212
- expect(Author.count).to eq(2)
213
- end
214
-
215
- it 'should replace authors by id' do
216
- expect(Author.find(1).name).to eq('John')
217
- expect(Author.find(2).name).to eq('Jane')
218
- end
219
- end
220
- end
221
-
222
- context 'with valid options' do
223
- let(:options) { {} }
224
-
225
- before do
226
- add_author_resource(options)
227
- visit '/admin/authors/import'
228
- end
229
-
230
- it 'has valid form' do
231
- form = find(ImportFormSelectors.form_css)
232
- expect(form['action']).to eq('/admin/authors/do_import')
233
- expect(form['enctype']).to eq('multipart/form-data')
234
- file_input = form.find(ImportFormSelectors.file_input_css)
235
- expect(file_input[:type]).to eq('file')
236
- expect(file_input.value).to be_blank
237
- submit_input = form.find(ImportFormSelectors.submit_css)
238
- expect(submit_input[:value]).to eq(ImportFormSelectors.import_button_text)
239
- expect(submit_input[:type]).to eq('submit')
240
- end
241
-
242
- context 'with hint defined' do
243
- let(:options) do
244
- { template_object: ActiveAdminImport::Model.new(hint: 'hint') }
245
- end
246
- it 'renders hint at upload page' do
247
- expect(page).to have_content options[:template_object].hint
248
- end
249
- end
250
-
251
- context 'when importing file' do
252
- [:empty, :only_headers].each do |file|
253
- context "when #{file} file" do
254
- it 'should render warning' do
255
- upload_file!(file)
256
- expect(page).to have_content I18n.t('active_admin_import.file_empty_error')
257
- expect(Author.count).to eq(0)
258
- end
259
- end
260
- end
261
-
262
- context 'when no file' do
263
- it 'should render error' do
264
- find_button(ImportFormSelectors.import_button_text).click
265
- expect(Author.count).to eq(0)
266
- expect(page).to have_content I18n.t('active_admin_import.no_file_error')
267
- end
268
- end
269
-
270
- context 'auto detect encoding' do
271
- include_examples 'successful inserts',
272
- :auto,
273
- :authors_win1251_win_endline
274
- end
275
-
276
- context 'Win1251' do
277
- include_examples 'successful inserts',
278
- 'windows-1251',
279
- :authors_win1251_win_endline
280
- end
281
-
282
- context 'BOM' do
283
- it 'should import file with many records' do
284
- upload_file!(:authors_bom)
285
- expect(page).to have_content 'Successfully imported 2 authors'
286
- expect(Author.count).to eq(2)
287
- end
288
- end
289
-
290
- context 'with headers' do
291
- it 'should import file with many records' do
292
- upload_file!(:authors)
293
- expect(page).to have_content 'Successfully imported 2 authors'
294
- expect(Author.count).to eq(2)
295
- end
296
-
297
- it 'should import file with 1 record' do
298
- upload_file!(:author)
299
- expect(page).to have_content 'Successfully imported 1 author'
300
- expect(Author.count).to eq(1)
301
- end
302
- end
303
-
304
- context 'without headers' do
305
- context 'with known csv headers' do
306
- let(:options) do
307
- attributes = { csv_headers: ['Name', 'Last name', 'Birthday'] }
308
- { template_object: ActiveAdminImport::Model.new(attributes) }
309
- end
310
-
311
- it 'should import file' do
312
- upload_file!(:authors_no_headers)
313
- expect(page).to have_content 'Successfully imported 2 authors'
314
- expect(Author.count).to eq(2)
315
- end
316
- end
317
-
318
- context 'with unknown csv headers' do
319
- it 'should render error' do
320
- upload_file!(:authors_no_headers)
321
- expect(page).to have_content 'Error:'
322
- expect(Author.count).to eq(0)
323
- end
324
- end
325
- end
326
-
327
- context 'with invalid data insert on DB constraint' do
328
- # :name field has an uniq index
329
- it 'should render error' do
330
- upload_file!(:authors_invalid_db)
331
- expect(page).to have_content 'Error:'
332
- expect(Author.count).to eq(0)
333
- end
334
- end
335
-
336
- context 'with invalid data insert on model validation' do
337
- let(:options) { { validate: true } }
338
-
339
- before do
340
- Author.create!(name: 'John', last_name: 'Doe')
341
- end
342
-
343
- it 'should render both successful and failed message' do
344
- upload_file!(:authors_invalid_model)
345
- expect(page).to have_content 'Failed to import 1 author'
346
- expect(page).to have_content 'Successfully imported 1 author'
347
- expect(page).to have_content 'Last name has already been taken - Doe'
348
- expect(Author.count).to eq(2)
349
- end
350
-
351
- context 'use batch_transaction to make transaction work on model validation' do
352
- let(:options) { { validate: true, batch_transaction: true } }
353
-
354
- it 'should render only the failed message' do
355
- upload_file!(:authors_invalid_model)
356
- expect(page).to have_content 'Failed to import 1 author'
357
- expect(page).to_not have_content 'Successfully imported'
358
- expect(Author.count).to eq(1)
359
- end
360
- end
361
- end
362
-
363
- context 'with invalid records' do
364
- context 'with validation' do
365
- it 'should render error' do
366
- upload_file!(:author_invalid)
367
- expect(page).to have_content 'Failed to import 1 author'
368
- expect(Author.count).to eq(0)
369
- end
370
- end
371
-
372
- context 'without validation' do
373
- let(:options) { { validate: false } }
374
- it 'should render error' do
375
- upload_file!(:author_invalid)
376
- expect(page).to have_content 'Successfully imported 1 author'
377
- expect(Author.count).to eq(1)
378
- end
379
- end
380
- end
381
-
382
- context 'when zipped' do
383
- context 'when allowed' do
384
- it 'should import file' do
385
- with_zipped_csv(:authors) do
386
- upload_file!(:authors, :zip)
387
- expect(page).to have_content 'Successfully imported 2 authors'
388
- expect(Author.count).to eq(2)
389
- end
390
- end
391
- end
392
-
393
- context 'when not allowed' do
394
- let(:options) do
395
- attributes = { allow_archive: false }
396
- { template_object: ActiveAdminImport::Model.new(attributes) }
397
- end
398
- it 'should render error' do
399
- with_zipped_csv(:authors) do
400
- upload_file!(:authors, :zip)
401
- expect(page).to have_content I18n.t('active_admin_import.file_format_error')
402
- expect(Author.count).to eq(0)
403
- end
404
- end
405
- end
406
-
407
- context 'when zipped with Win1251 file' do
408
- let(:options) do
409
- attributes = { force_encoding: :auto }
410
- { template_object: ActiveAdminImport::Model.new(attributes) }
411
- end
412
- it 'should import file' do
413
- with_zipped_csv(:authors_win1251_win_endline) do
414
- upload_file!(:authors_win1251_win_endline, :zip)
415
- expect(page).to have_content 'Successfully imported 2 authors'
416
- expect(Author.count).to eq(2)
417
- end
418
- end
419
- end
420
- end
421
-
422
- context 'with different header attribute names' do
423
- let(:options) do
424
- { headers_rewrites: { :'Second name' => :last_name } }
425
- end
426
-
427
- it 'should import file' do
428
- upload_file!(:author_broken_header)
429
- expect(page).to have_content 'Successfully imported 1 author'
430
- expect(Author.count).to eq(1)
431
- end
432
- end
433
-
434
- context 'with semicolons separator' do
435
- let(:options) do
436
- attributes = { csv_options: { col_sep: ';' } }
437
- { template_object: ActiveAdminImport::Model.new(attributes) }
438
- end
439
-
440
- it 'should import file' do
441
- upload_file!(:authors_with_semicolons)
442
- expect(page).to have_content 'Successfully imported 2 authors'
443
- expect(Author.count).to eq(2)
444
- end
445
- end
446
-
447
- context 'with tab separator' do
448
- let(:options) do
449
- attributes = { csv_options: { col_sep: "\t" } }
450
- { template_object: ActiveAdminImport::Model.new(attributes) }
451
- end
452
-
453
- it 'should import file' do
454
- upload_file!(:authors_with_tabs, 'tsv')
455
- expect(page).to have_content 'Successfully imported 2 authors'
456
- expect(Author.count).to eq(2)
457
- end
458
- end
459
-
460
- context 'with empty csv and auto detect encoding' do
461
- let(:options) do
462
- attributes = { force_encoding: :auto }
463
- { template_object: ActiveAdminImport::Model.new(attributes) }
464
- end
465
-
466
- before do
467
- upload_file!(:empty)
468
- end
469
-
470
- it 'should render warning' do
471
- expect(page).to have_content I18n.t('active_admin_import.file_empty_error')
472
- expect(Author.count).to eq(0)
473
- end
474
- end
475
-
476
- context 'with csv which has exceeded values' do
477
- before do
478
- upload_file!(:authors_values_exceeded_headers)
479
- end
480
-
481
- it 'should render warning' do
482
- # 5 columns: 'birthday, name, last_name, created_at, updated_at'
483
- # 6 values: '"1988-11-16", "Jane", "Roe", " exceeded value", datetime, datetime'
484
- msg = 'Number of values (6) exceeds number of columns (5)'
485
- expect(page).to have_content I18n.t('active_admin_import.file_error', message: msg)
486
- expect(Author.count).to eq(0)
487
- end
488
- end
489
- end
490
-
491
- context 'with callback procs options' do
492
- let(:options) do
493
- {
494
- before_import: ->(_) { true },
495
- after_import: ->(_) { true },
496
- before_batch_import: ->(_) { true },
497
- after_batch_import: ->(_) { true }
498
- }
499
- end
500
-
501
- it 'should call each callback' do
502
- expect(options[:before_import]).to receive(:call).with(kind_of(ActiveAdminImport::Importer))
503
- expect(options[:after_import]).to receive(:call).with(kind_of(ActiveAdminImport::Importer))
504
- expect(options[:before_batch_import]).to receive(:call).with(kind_of(ActiveAdminImport::Importer))
505
- expect(options[:after_batch_import]).to receive(:call).with(kind_of(ActiveAdminImport::Importer))
506
- upload_file!(:authors)
507
- expect(Author.count).to eq(2)
508
- end
509
-
510
- context 'when the option before_import raises a ActiveAdminImport::Exception' do
511
- let(:options) { { before_import: ->(_) { raise ActiveAdminImport::Exception, 'error message' } } }
512
-
513
- before { upload_file!(:authors) }
514
-
515
- it 'should show error' do
516
- expect(page).to have_content I18n.t('active_admin_import.file_error', message: 'error message')
517
- expect(Author.count).to eq(0)
518
- end
519
- end
520
-
521
- context 'when the option before_batch_import raises a ActiveAdminImport::Exception' do
522
- let(:options) { { before_batch_import: ->(_) { raise ActiveAdminImport::Exception, 'error message' } } }
523
-
524
- before { upload_file!(:authors) }
525
-
526
- it 'should show error' do
527
- expect(page).to have_content I18n.t('active_admin_import.file_error', message: 'error message')
528
- expect(Author.count).to eq(0)
529
- end
530
- end
531
- end
532
- end
533
-
534
- context "with slice_columns option" do
535
- let(:batch_size) { 2 }
536
-
537
- before do
538
- add_author_resource template_object: ActiveAdminImport::Model.new,
539
- before_batch_import: lambda { |importer|
540
- importer.batch_slice_columns(slice_columns)
541
- },
542
- batch_size: batch_size
543
- visit "/admin/authors/import"
544
- upload_file!(:authors)
545
- end
546
-
547
- context "slice last column and superfluous column" do
548
- let(:slice_columns) { %w(name last_name not_existing_column) }
549
-
550
- shared_examples_for "birthday column removed" do
551
- it "should not fill `birthday` column" do
552
- expect(Author.pluck(:name, :last_name, :birthday)).to match_array(
553
- [
554
- ["Jane", "Roe", nil],
555
- ["John", "Doe", nil]
556
- ]
557
- )
558
- end
559
- end
560
-
561
- it_behaves_like "birthday column removed"
562
-
563
- context "when doing more than one batch" do
564
- let(:batch_size) { 1 }
565
-
566
- it_behaves_like "birthday column removed"
567
- end
568
- end
569
-
570
- context "slice column from the middle" do
571
- let(:slice_columns) { %w(name birthday) }
572
-
573
- it "should not fill `last_name` column" do
574
- expect(Author.pluck(:name, :last_name, :birthday)).to match_array(
575
- [
576
- ["Jane", nil, "1988-11-16".to_date],
577
- ["John", nil, "1986-05-01".to_date]
578
- ]
579
- )
580
- end
581
- end
582
- end
583
-
584
- context 'with invalid options' do
585
- let(:options) { { invalid_option: :invalid_value } }
586
-
587
- it 'should raise TypeError' do
588
- expect { add_author_resource(options) }.to raise_error(ArgumentError)
589
- end
590
- end
591
-
592
- context 'when submitting empty form after validation error' do
593
- let(:options) { {} }
594
-
595
- before do
596
- add_author_resource(options)
597
- visit '/admin/authors/import'
598
- end
599
-
600
- it 'should NOT reuse cached file from previous submission' do
601
- expect do
602
- upload_file!(:author_broken_header)
603
- expect(page).to have_content("can't write unknown attribute")
604
- end.not_to change { Author.count }
605
-
606
- # Second submission without selecting a file
607
- expect do
608
- find_button(ImportFormSelectors.import_button_text).click
609
- expect(page).to have_content(I18n.t('active_admin_import.no_file_error'))
610
- end.not_to change { Author.count }
611
- end
612
- end
613
-
614
- context 'when importing file with invalid format and auto force_encoding' do
615
- let(:options) { { template_object: ActiveAdminImport::Model.new(force_encoding: :auto) } }
616
-
617
- before do
618
- add_author_resource(options)
619
- visit '/admin/authors/import'
620
- end
621
-
622
- it 'should reject invalid file format before encoding' do
623
- expect do
624
- upload_file!(:author_invalid_format, 'txt')
625
- expect(page).to have_content I18n.t('active_admin_import.file_format_error')
626
- end.not_to change { Author.count }
627
- end
628
- end
629
-
630
- context 'with active_admin_import_context defined on the controller' do
631
- before { Author.create!(name: 'John', last_name: 'Doe') }
632
-
633
- let(:author) { Author.take }
634
-
635
- context 'when context returns request-derived attributes' do
636
- before do
637
- author_id = author.id
638
- add_post_resource(
639
- template_object: ActiveAdminImport::Model.new(author_id: author_id),
640
- before_batch_import: lambda do |importer|
641
- ip = importer.model.request_ip
642
- a_id = importer.model.author_id
643
- importer.csv_lines.map! { |row| row << ip << a_id }
644
- importer.headers.merge!(:'Request Ip' => :request_ip, :'Author Id' => :author_id)
645
- end,
646
- controller_block: proc do
647
- def active_admin_import_context
648
- { request_ip: request.remote_ip }
649
- end
650
- end
651
- )
652
- visit '/admin/posts/import'
653
- upload_file!(:posts_for_author)
654
- end
655
-
656
- it 'merges the context into the import model so callbacks see it' do
657
- expect(page).to have_content 'Successfully imported 2 posts'
658
- expect(Post.count).to eq(2)
659
- Post.all.each do |post|
660
- expect(post.request_ip).to eq('127.0.0.1')
661
- expect(post.author_id).to eq(author.id)
662
- end
663
- end
664
- end
665
-
666
- context 'when context returns parent id for a nested belongs_to resource' do
667
- let(:post) { Post.create!(title: 'A post', body: 'body', author: author) }
668
-
669
- before do
670
- add_nested_post_comment_resource(
671
- before_batch_import: lambda do |importer|
672
- importer.csv_lines.map! { |row| row << importer.model.post_id }
673
- importer.headers.merge!(:'Post Id' => :post_id)
674
- end,
675
- controller_block: proc do
676
- def active_admin_import_context
677
- { post_id: parent.id }
678
- end
679
- end
680
- )
681
- visit "/admin/posts/#{post.id}/post_comments/import"
682
- upload_file!(:post_comments)
683
- end
684
-
685
- it 'automatically assigns the parent post_id to every imported comment' do
686
- expect(page).to have_content 'Successfully imported 2 post comments'
687
- expect(PostComment.count).to eq(2)
688
- expect(PostComment.where(post_id: post.id).count).to eq(2)
689
- end
690
- end
691
- 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
734
- end