active_admin_import 5.1.0 → 6.0.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 84ba0d9c89bd483eef55da51f9a06ec6327c4bbfffa79abc8431e578bb347c26
4
- data.tar.gz: 9c13aefd9dc6397c7fee814ca4f4f7251d9cfb8c399249570acf902b928eacab
3
+ metadata.gz: bdc784c6f8a845b491b0dc93e44b073b548bccc182bb3cf6c26cb9f80e59b587
4
+ data.tar.gz: 798237101d7d4403ed8fb1d1d4ed466b4b78bc44740e20137887d2c8b6464e3f
5
5
  SHA512:
6
- metadata.gz: bad8987eeac221884549f9c36d28ced4afc5ed02ee6b65cbf68436053d1ac19644d270e3c20b10aa00b4eb7117289d030e8970036331e803716be6ac10a4bd8c
7
- data.tar.gz: 3c8dd843c7fbdb989417a9a0a2611f0c66759f4662c02ed101d37bf36d51f15ecf4b88c49353599f4df5e978f6e19a36eab17cab8be4b65e985594665afc3080
6
+ metadata.gz: '06639b5514e0c5af1f2cfd70f66f7de10b798fc22f9153b4870c0859b3f95fd372cf73f406b15b7df8b3e4d6fc350a911680248e09d15412479c55f092869a0d'
7
+ data.tar.gz: 1b49c36c911a6eae50d653eafa4063a139b5d901b81264b213ece4bb995158bf7685f62facce2d5d1a69b76fe2735483296a26f9f697f6fad802d562ca3deef5
@@ -1,43 +1,162 @@
1
- name: Test
2
-
1
+ name: CI
3
2
  on:
4
- - push
5
- - pull_request
3
+ pull_request:
4
+ push:
5
+ branches: [master]
6
+
7
+ permissions:
8
+ contents: read
9
+ pages: write
10
+ id-token: write
6
11
 
7
12
  jobs:
8
- build:
13
+ test:
14
+ name: Ruby ${{ matrix.ruby }} / Rails ${{ matrix.rails }} / AA ${{ matrix.activeadmin }} / SQLite
9
15
  runs-on: ubuntu-latest
10
-
11
16
  strategy:
17
+ fail-fast: false
12
18
  matrix:
13
- ruby_version:
14
- - '2.6'
15
- - '2.7'
16
- - '3.0'
17
- rails_version:
18
- - '5.2.6'
19
- - '6.0.4'
20
- - '6.1.4'
21
- - '7.0.0'
19
+ ruby: ['3.2', '3.3', '3.4']
20
+ rails: ['7.1.0', '7.2.0', '8.0.0']
21
+ activeadmin: ['3.2.0', '3.3.0', '3.4.0', '3.5.1']
22
22
  exclude:
23
- - ruby_version: '3.0'
24
- rails_version: '5.2.6'
25
- - ruby_version: '2.6'
26
- rails_version: '7.0.0'
27
-
28
- name: Ruby ${{ matrix.ruby_version }} / Rails ${{ matrix.rails_version }}
29
-
23
+ - rails: '8.0.0'
24
+ activeadmin: '3.2.0'
30
25
  env:
31
- RAILS: ${{ matrix.rails_version }}
32
-
26
+ RAILS: ${{ matrix.rails }}
27
+ AA: ${{ matrix.activeadmin }}
33
28
  steps:
34
- - uses: actions/checkout@v2
35
-
36
- - name: Setup Ruby
37
- uses: ruby/setup-ruby@v1
29
+ - uses: actions/checkout@v4
30
+ - uses: ruby/setup-ruby@v1
38
31
  with:
39
- ruby-version: ${{ matrix.ruby_version }}
32
+ ruby-version: ${{ matrix.ruby }}
40
33
  bundler-cache: true
41
-
42
- - name: Test
34
+ - name: Run tests
35
+ run: bundle exec rspec spec
36
+ test-mysql:
37
+ name: Ruby 3.4 / Rails 8.0.0 / AA 3.5.1 / MySQL 8.0
38
+ runs-on: ubuntu-latest
39
+ env:
40
+ RAILS: '8.0.0'
41
+ AA: '3.5.1'
42
+ DB: mysql
43
+ DB_HOST: 127.0.0.1
44
+ DB_PORT: 3306
45
+ DB_USERNAME: root
46
+ DB_PASSWORD: root
47
+ services:
48
+ mysql:
49
+ image: mysql:8.0
50
+ env:
51
+ MYSQL_ROOT_PASSWORD: root
52
+ MYSQL_DATABASE: active_admin_import_test
53
+ ports:
54
+ - 3306:3306
55
+ options: >-
56
+ --health-cmd="mysqladmin ping -h localhost -uroot -proot"
57
+ --health-interval=10s
58
+ --health-timeout=5s
59
+ --health-retries=10
60
+ steps:
61
+ - uses: actions/checkout@v4
62
+ - uses: ruby/setup-ruby@v1
63
+ with:
64
+ ruby-version: '3.4'
65
+ bundler-cache: true
66
+ - name: Run tests
67
+ run: bundle exec rspec spec
68
+ test-postgres:
69
+ name: Ruby 3.4 / Rails 8.0.0 / AA 3.5.1 / PostgreSQL 16
70
+ runs-on: ubuntu-latest
71
+ env:
72
+ RAILS: '8.0.0'
73
+ AA: '3.5.1'
74
+ DB: postgres
75
+ DB_HOST: 127.0.0.1
76
+ DB_PORT: 5432
77
+ DB_USERNAME: postgres
78
+ DB_PASSWORD: postgres
79
+ services:
80
+ postgres:
81
+ image: postgres:16
82
+ env:
83
+ POSTGRES_USER: postgres
84
+ POSTGRES_PASSWORD: postgres
85
+ POSTGRES_DB: active_admin_import_test
86
+ ports:
87
+ - 5432:5432
88
+ options: >-
89
+ --health-cmd="pg_isready -U postgres"
90
+ --health-interval=10s
91
+ --health-timeout=5s
92
+ --health-retries=10
93
+ steps:
94
+ - uses: actions/checkout@v4
95
+ - uses: ruby/setup-ruby@v1
96
+ with:
97
+ ruby-version: '3.4'
98
+ bundler-cache: true
99
+ - name: Run tests
43
100
  run: bundle exec rspec spec
101
+ coverage:
102
+ name: Coverage
103
+ runs-on: ubuntu-latest
104
+ steps:
105
+ - uses: actions/checkout@v4
106
+ - uses: ruby/setup-ruby@v1
107
+ with:
108
+ ruby-version: '3.4'
109
+ bundler-cache: true
110
+ - name: Run tests with coverage
111
+ run: bundle exec rspec spec
112
+ - name: Upload coverage
113
+ uses: actions/upload-artifact@v4
114
+ with:
115
+ name: coverage
116
+ path: coverage/
117
+
118
+ - name: Generate badge.json
119
+ run: |
120
+ LAST_RUN="coverage/.last_run.json"
121
+ if [ ! -f "$LAST_RUN" ]; then
122
+ mkdir -p badge
123
+ echo '{"schemaVersion":1,"label":"coverage","message":"unknown","color":"lightgrey"}' > badge/badge.json
124
+ exit 0
125
+ fi
126
+ PERCENT=$(ruby -rjson -e "puts JSON.parse(File.read('$LAST_RUN')).dig('result','line').round(1)")
127
+ PERCENT_NUM=$(ruby -rjson -e "puts JSON.parse(File.read('$LAST_RUN')).dig('result','line')")
128
+ if ruby -e "exit(($PERCENT_NUM >= 90) ? 0 : 1)"; then COLOR="brightgreen"
129
+ elif ruby -e "exit(($PERCENT_NUM >= 75) ? 0 : 1)"; then COLOR="green"
130
+ elif ruby -e "exit(($PERCENT_NUM >= 60) ? 0 : 1)"; then COLOR="yellow"
131
+ else COLOR="red"; fi
132
+ mkdir -p badge
133
+ echo "{\"schemaVersion\":1,\"label\":\"coverage\",\"message\":\"${PERCENT}%\",\"color\":\"${COLOR}\"}" > badge/badge.json
134
+
135
+ - name: Upload badge artifact
136
+ uses: actions/upload-artifact@v4
137
+ with:
138
+ name: coverage-badge
139
+ path: badge
140
+
141
+ deploy-coverage:
142
+ needs: coverage
143
+ if: github.ref == 'refs/heads/master' && github.event_name == 'push'
144
+ runs-on: ubuntu-latest
145
+ environment:
146
+ name: github-pages
147
+ url: ${{ steps.deployment.outputs.page_url }}
148
+ steps:
149
+ - name: Download coverage badge
150
+ uses: actions/download-artifact@v4
151
+ with:
152
+ name: coverage-badge
153
+ path: .
154
+ - name: Setup Pages
155
+ uses: actions/configure-pages@v5
156
+ - name: Upload Pages artifact
157
+ uses: actions/upload-pages-artifact@v3
158
+ with:
159
+ path: .
160
+ - name: Deploy to GitHub Pages
161
+ id: deployment
162
+ uses: actions/deploy-pages@v4
data/Gemfile CHANGED
@@ -1,21 +1,27 @@
1
- # frozen_string_literal: true
2
1
  source 'https://rubygems.org'
3
-
4
- # Specify your gem's dependencies in active_admin_importable.gemspec
5
2
  gemspec
6
3
 
4
+ default_rails_version = '7.1.0'
5
+ default_activeadmin_version = '3.2.0'
6
+
7
+ gem 'rails', "~> #{ENV['RAILS'] || default_rails_version}"
8
+ gem 'activeadmin', "~> #{ENV['AA'] || default_activeadmin_version}"
9
+ gem 'sprockets-rails'
10
+ gem 'sass-rails'
7
11
 
8
12
  group :test do
9
- default_rails_version = "~> 5.2.4"
10
- rails_version = ENV['RAILS'] || default_rails_version
11
- gem 'sassc-rails'
12
- gem 'rails', rails_version
13
+ gem 'simplecov', require: false
13
14
  gem 'rspec-rails'
14
- gem 'coveralls', require: false # Test coverage website. Go to https://coveralls.io
15
- gem "sqlite3", "~> 1.4.0"
16
- gem 'launchy'
15
+ case ENV['DB']
16
+ when 'mysql'
17
+ gem 'mysql2'
18
+ when 'postgres', 'postgresql'
19
+ gem 'pg'
20
+ else
21
+ gem 'sqlite3', '~> 2.0'
22
+ end
17
23
  gem 'database_cleaner'
18
24
  gem 'capybara'
19
- gem 'poltergeist'
20
- gem 'jquery-ui-rails', '~> 5.0'
25
+ gem 'cuprite'
26
+ gem 'webrick', require: false
21
27
  end
data/README.md CHANGED
@@ -1,15 +1,13 @@
1
1
  # ActiveAdminImport
2
2
 
3
- [![Build Status ][build_badge]][build_link]
4
- [![Coverage Status][coveralls_badge]][coveralls_link]
5
- [![Code Climate ][codeclimate_badge]][codeclimate_link]
6
- [![Gem Version ][rubygems_badge]][rubygems_link]
7
- [![License ][license_badge]][license_link]
3
+ [![Build Status][build_badge]][build_link]
4
+ ![Coverage][coverage_badge]
5
+ [![Code Climate][codeclimate_badge]][codeclimate_link]
6
+ [![Gem Version][rubygems_badge]][rubygems_link]
7
+ [![License][license_badge]][license_link]
8
8
 
9
9
 
10
- The most fastest and efficient CSV import for Active Admin with support of validations, bulk inserts and encodings handling.
11
-
12
- For more about ActiveAdminImport installation and usage, check [Documentation website](http://activeadmin-plugins.github.io/active_admin_import/) and [Wiki pages](https://github.com/activeadmin-plugins/active_admin_import/wiki) for some specific cases and caveats.
10
+ The fastest and most efficient CSV import for Active Admin with support for validations, bulk inserts, and encoding handling.
13
11
 
14
12
 
15
13
  ## Installation
@@ -44,7 +42,7 @@ And then execute:
44
42
  #### Basic usage
45
43
 
46
44
  ```ruby
47
- ActiveAdmin.register Post
45
+ ActiveAdmin.register Post do
48
46
  active_admin_import options
49
47
  end
50
48
  ```
@@ -68,6 +66,7 @@ Tool | Description
68
66
  :timestamps |bool, tells activerecord-import to not add timestamps (if false) even if record timestamps is disabled in ActiveRecord::Base
69
67
  :template |custom template rendering
70
68
  :template_object |object passing to view
69
+ :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`).
71
70
  :resource_class |resource class name
72
71
  :resource_label |resource label value
73
72
  :plural_resource_label |pluralized resource label value (default config.plural_resource_label)
@@ -77,9 +76,248 @@ Tool | Description
77
76
 
78
77
 
79
78
 
80
- #### Wiki
79
+ #### Custom ImportResult
80
+
81
+ 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`:
82
+
83
+ ```ruby
84
+ class ImportResultWithIds < ActiveAdminImport::ImportResult
85
+ attr_reader :ids
86
+
87
+ def initialize
88
+ super
89
+ @ids = []
90
+ end
91
+
92
+ def add(batch_result, qty)
93
+ super
94
+ @ids.concat(Array(batch_result.ids))
95
+ end
96
+ end
97
+
98
+ ActiveAdmin.register Author do
99
+ active_admin_import result_class: ImportResultWithIds do |result, options|
100
+ EnqueueAuthorsJob.perform_later(result.ids) if result.imported?
101
+ instance_exec(result, options, &ActiveAdminImport::DSL::DEFAULT_RESULT_PROC)
102
+ end
103
+ end
104
+ ```
105
+
106
+ 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.
107
+
108
+ 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.
109
+
110
+
111
+ #### Authorization
112
+
113
+ The current user must be authorized to perform imports. With CanCanCan:
114
+
115
+ ```ruby
116
+ class Ability
117
+ include CanCan::Ability
118
+
119
+ def initialize(user)
120
+ can :import, Post
121
+ end
122
+ end
123
+ ```
124
+
125
+
126
+ #### Per-request context
127
+
128
+ Define an `active_admin_import_context` method on the controller to inject request-derived attributes into every import (current user, parent resource id, request IP, etc.). The returned hash is merged into the import model after form params, so it always wins for the keys it provides:
129
+
130
+ ```ruby
131
+ ActiveAdmin.register PostComment do
132
+ belongs_to :post
133
+
134
+ controller do
135
+ def active_admin_import_context
136
+ { post_id: parent.id, request_ip: request.remote_ip }
137
+ end
138
+ end
139
+
140
+ active_admin_import before_batch_import: ->(importer) {
141
+ importer.csv_lines.map! { |row| row << importer.model.post_id }
142
+ importer.headers.merge!(:'Post Id' => :post_id)
143
+ }
144
+ end
145
+ ```
146
+
147
+
148
+ #### Examples
149
+
150
+ ##### Files without CSV headers
151
+
152
+ ```ruby
153
+ ActiveAdmin.register Post do
154
+ active_admin_import validate: true,
155
+ template_object: ActiveAdminImport::Model.new(
156
+ hint: "expected header order: body, title, author",
157
+ csv_headers: %w[body title author]
158
+ )
159
+ end
160
+ ```
161
+
162
+ ##### Auto-detect file encoding
163
+
164
+ ```ruby
165
+ ActiveAdmin.register Post do
166
+ active_admin_import validate: true,
167
+ template_object: ActiveAdminImport::Model.new(force_encoding: :auto)
168
+ end
169
+ ```
170
+
171
+ ##### Force a specific (non-UTF-8) encoding
172
+
173
+ ```ruby
174
+ ActiveAdmin.register Post do
175
+ active_admin_import validate: true,
176
+ template_object: ActiveAdminImport::Model.new(
177
+ hint: "file is encoded in ISO-8859-1",
178
+ force_encoding: "ISO-8859-1"
179
+ )
180
+ end
181
+ ```
182
+
183
+ ##### Disallow ZIP upload
184
+
185
+ ```ruby
186
+ ActiveAdmin.register Post do
187
+ active_admin_import validate: true,
188
+ template_object: ActiveAdminImport::Model.new(
189
+ hint: "upload a CSV file",
190
+ allow_archive: false
191
+ )
192
+ end
193
+ ```
194
+
195
+ ##### Skip CSV columns
196
+
197
+ Useful when the CSV file has columns that don't exist on the table. Available since 3.1.0.
198
+
199
+ ```ruby
200
+ ActiveAdmin.register Post do
201
+ active_admin_import before_batch_import: ->(importer) {
202
+ importer.batch_slice_columns(['name', 'last_name'])
203
+ }
204
+ end
205
+ ```
206
+
207
+ Tip: pass `Post.column_names` to keep only the columns that exist on the table.
208
+
209
+ ##### Resolve associations on the fly
210
+
211
+ Replace an `Author name` column in the CSV with the matching `author_id` before insert:
212
+
213
+ ```ruby
214
+ ActiveAdmin.register Post do
215
+ active_admin_import validate: true,
216
+ headers_rewrites: { 'Author name': :author_id },
217
+ before_batch_import: ->(importer) {
218
+ names = importer.values_at(:author_id)
219
+ mapping = Author.where(name: names).pluck(:name, :id).to_h
220
+ importer.batch_replace(:author_id, mapping)
221
+ }
222
+ end
223
+ ```
224
+
225
+ ##### Update existing records by id
226
+
227
+ Delete colliding rows just before each batch insert:
228
+
229
+ ```ruby
230
+ ActiveAdmin.register Post do
231
+ active_admin_import before_batch_import: ->(importer) {
232
+ Post.where(id: importer.values_at('id')).delete_all
233
+ }
234
+ end
235
+ ```
236
+
237
+ For databases that support upserts you can use `:on_duplicate_key_update` instead.
238
+
239
+ ##### Tune batch size
240
+
241
+ ```ruby
242
+ ActiveAdmin.register Post do
243
+ active_admin_import validate: false,
244
+ csv_options: { col_sep: ";" },
245
+ batch_size: 1000
246
+ end
247
+ ```
248
+
249
+ ##### Import into an intermediate table
250
+
251
+ ```ruby
252
+ ActiveAdmin.register Post do
253
+ active_admin_import validate: false,
254
+ csv_options: { col_sep: ";" },
255
+ resource_class: ImportedPost, # write to a staging table
256
+ before_import: ->(_) { ImportedPost.delete_all },
257
+ after_import: ->(_) {
258
+ Post.transaction do
259
+ Post.delete_all
260
+ Post.connection.execute("INSERT INTO posts (SELECT * FROM imported_posts)")
261
+ end
262
+ },
263
+ back: ->(_) { config.namespace.resource_for(Post).route_collection_path }
264
+ end
265
+ ```
266
+
267
+ ##### Allow user input for CSV options (custom template)
268
+
269
+ ```ruby
270
+ ActiveAdmin.register Post do
271
+ active_admin_import validate: false,
272
+ template: 'admin/posts/import',
273
+ template_object: ActiveAdminImport::Model.new(
274
+ hint: "you can configure CSV options",
275
+ csv_options: { col_sep: ";", row_sep: nil, quote_char: nil }
276
+ )
277
+ end
278
+ ```
279
+
280
+ `app/views/admin/posts/import.html.erb`:
281
+
282
+ ```erb
283
+ <p><%= raw(@active_admin_import_model.hint) %></p>
284
+
285
+ <%= semantic_form_for @active_admin_import_model, url: { action: :do_import }, html: { multipart: true } do |f| %>
286
+ <%= f.inputs do %>
287
+ <%= f.input :file, as: :file %>
288
+ <% end %>
289
+
290
+ <%= f.inputs "CSV options", for: [:csv_options, OpenStruct.new(@active_admin_import_model.csv_options)] do |csv| %>
291
+ <% csv.with_options input_html: { style: 'width:40px;' } do |opts| %>
292
+ <%= opts.input :col_sep %>
293
+ <%= opts.input :row_sep %>
294
+ <%= opts.input :quote_char %>
295
+ <% end %>
296
+ <% end %>
297
+
298
+ <%= f.actions do %>
299
+ <%= f.action :submit,
300
+ label: t("active_admin_import.import_btn"),
301
+ button_html: { disable_with: t("active_admin_import.import_btn_disabled") } %>
302
+ <% end %>
303
+ <% end %>
304
+ ```
305
+
306
+ ##### Inspecting the importer in batch callbacks
307
+
308
+ Both `before_batch_import` and `after_batch_import` receive the `Importer` instance:
309
+
310
+ ```ruby
311
+ active_admin_import before_batch_import: ->(importer) {
312
+ importer.file # the uploaded file
313
+ importer.resource # the ActiveRecord class being imported into
314
+ importer.options # the resolved options hash
315
+ importer.headers # CSV headers (mutable)
316
+ importer.csv_lines # parsed CSV rows for the current batch (mutable)
317
+ importer.model # the template_object instance
318
+ }
319
+ ```
81
320
 
82
- [Check various examples](https://github.com/activeadmin-plugins/active_admin_import/wiki)
83
321
 
84
322
  ## Dependencies
85
323
 
@@ -93,14 +331,13 @@ Tool | Description
93
331
 
94
332
  [build_badge]: https://github.com/activeadmin-plugins/active_admin_import/actions/workflows/test.yml/badge.svg
95
333
  [build_link]: https://github.com/activeadmin-plugins/active_admin_import/actions
96
- [coveralls_badge]: https://coveralls.io/repos/activeadmin-plugins/active_admin_import/badge.svg
97
- [coveralls_link]: https://coveralls.io/github/activeadmin-plugins/active_admin_import
334
+ [coverage_badge]: https://img.shields.io/endpoint?url=https://activeadmin-plugins.github.io/active_admin_import/badge.json
98
335
  [codeclimate_badge]: https://codeclimate.com/github/activeadmin-plugins/active_admin_import/badges/gpa.svg
99
336
  [codeclimate_link]: https://codeclimate.com/github/activeadmin-plugins/active_admin_import
100
337
  [rubygems_badge]: https://badge.fury.io/rb/active_admin_import.svg
101
338
  [rubygems_link]: https://rubygems.org/gems/active_admin_import
102
- [license_badge]: http://img.shields.io/:license-mit-blue.svg
103
- [license_link]: http://Fivell.mit-license.org
339
+ [license_badge]: https://img.shields.io/:license-mit-blue.svg
340
+ [license_link]: https://Fivell.mit-license.org
104
341
 
105
342
 
106
343
  ## Contributing
data/Rakefile CHANGED
@@ -1,8 +1,5 @@
1
- # frozen_string_literal: true
2
- require 'bundler'
1
+ require "bundler"
3
2
  require 'rake'
4
3
  Bundler.setup
5
4
  Bundler::GemHelper.install_tasks
6
-
7
- # Import all our rake tasks
8
5
  FileList['tasks/**/*.rake'].each { |task| import task }
@@ -7,16 +7,16 @@ Gem::Specification.new do |gem|
7
7
  gem.email = ['fedoronchuk@gmail.com']
8
8
  gem.description = 'The most efficient way to import for Active Admin'
9
9
  gem.summary = 'ActiveAdmin import based on activerecord-import gem.'
10
- gem.homepage = 'http://github.com/Fivell/active_admin_import'
10
+ gem.homepage = 'https://github.com/activeadmin-plugins/active_admin_import'
11
11
  gem.license = 'MIT'
12
+ gem.required_ruby_version = '>= 3.1.0'
12
13
  gem.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
13
14
  gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
14
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
15
  gem.name = 'active_admin_import'
16
16
  gem.require_paths = ['lib']
17
17
  gem.version = ActiveAdminImport::VERSION
18
- gem.add_runtime_dependency 'activerecord-import', '>= 0.27'
18
+ gem.add_runtime_dependency 'activerecord-import', '>= 2.0'
19
19
  gem.add_runtime_dependency 'rchardet', '>= 1.6'
20
20
  gem.add_runtime_dependency 'rubyzip', '>= 1.2'
21
- gem.add_dependency 'activeadmin', '>= 1.0.0'
21
+ gem.add_dependency 'activeadmin', '>= 3.0', '< 4.0'
22
22
  end
@@ -25,6 +25,22 @@ module ActiveAdminImport
25
25
  # +plural_resource_label+:: pluralized resource label value (default config.plural_resource_label)
26
26
  #
27
27
  module DSL
28
+ CONTEXT_METHOD = :active_admin_import_context
29
+
30
+ def self.prepare_import_model(template_object, controller, params: nil)
31
+ model = template_object.is_a?(Proc) ? template_object.call : template_object
32
+ if params
33
+ params_key = ActiveModel::Naming.param_key(model.class)
34
+ model.assign_attributes(params[params_key].try(:deep_symbolize_keys) || {})
35
+ end
36
+ return model unless controller.respond_to?(CONTEXT_METHOD, true)
37
+ context = controller.send(CONTEXT_METHOD)
38
+ return model unless context.is_a?(Hash)
39
+ context = context.merge(file: model.file) if model.respond_to?(:file) && !context.key?(:file)
40
+ model.assign_attributes(context)
41
+ model
42
+ end
43
+
28
44
  DEFAULT_RESULT_PROC = lambda do |result, options|
29
45
  model_name = options[:resource_label].downcase
30
46
  plural_model_name = options[:plural_resource_label].downcase
@@ -57,11 +73,7 @@ module ActiveAdminImport
57
73
 
58
74
  collection_action :import, method: :get do
59
75
  authorize!(ActiveAdminImport::Auth::IMPORT, active_admin_config.resource_class)
60
- @active_admin_import_model = if options[:template_object].is_a?(Proc)
61
- options[:template_object].call
62
- else
63
- options[:template_object]
64
- end
76
+ @active_admin_import_model = ActiveAdminImport::DSL.prepare_import_model(options[:template_object], self)
65
77
  render template: options[:template]
66
78
  end
67
79
 
@@ -78,13 +90,9 @@ module ActiveAdminImport
78
90
  authorize!(ActiveAdminImport::Auth::IMPORT, active_admin_config.resource_class)
79
91
  _params = params.respond_to?(:to_unsafe_h) ? params.to_unsafe_h : params
80
92
  params = ActiveSupport::HashWithIndifferentAccess.new _params
81
- @active_admin_import_model = if options[:template_object].is_a?(Proc)
82
- options[:template_object].call
83
- else
84
- options[:template_object]
85
- end
86
- params_key = ActiveModel::Naming.param_key(@active_admin_import_model.class)
87
- @active_admin_import_model.assign_attributes(params[params_key].try(:deep_symbolize_keys) || {})
93
+ @active_admin_import_model = ActiveAdminImport::DSL.prepare_import_model(
94
+ options[:template_object], self, params: params
95
+ )
88
96
  # go back to form
89
97
  return render template: options[:template] unless @active_admin_import_model.valid?
90
98
  @importer = Importer.new(
@@ -96,7 +104,7 @@ module ActiveAdminImport
96
104
  result = @importer.import
97
105
 
98
106
  if block_given?
99
- instance_eval(&block)
107
+ instance_exec result, options, &block
100
108
  else
101
109
  instance_exec result, options, &DEFAULT_RESULT_PROC
102
110
  end
@@ -18,7 +18,8 @@ module ActiveAdminImport
18
18
  :headers_rewrites,
19
19
  :batch_size,
20
20
  :batch_transaction,
21
- :csv_options
21
+ :csv_options,
22
+ :result_class
22
23
  ].freeze
23
24
 
24
25
  def initialize(resource, model, options)
@@ -29,7 +30,7 @@ module ActiveAdminImport
29
30
  end
30
31
 
31
32
  def import_result
32
- @import_result ||= ImportResult.new
33
+ @import_result ||= (options[:result_class] || ImportResult).new
33
34
  end
34
35
 
35
36
  def file
@@ -37,7 +37,7 @@ module ActiveAdminImport
37
37
  validate :file_contents_present, if: ->(me) { me.file.present? }
38
38
 
39
39
  before_validation :unzip_file, if: ->(me) { me.archive? && me.allow_archive? }
40
- before_validation :encode_file, if: ->(me) { me.force_encoding? && me.file.present? }
40
+ after_validation :encode_file, if: ->(me) { me.errors.empty? && me.force_encoding? && me.file.present? }
41
41
 
42
42
  attr_reader :attributes
43
43
 
@@ -48,6 +48,7 @@ module ActiveAdminImport
48
48
  end
49
49
 
50
50
  def assign_attributes(args = {}, new_record = false)
51
+ args[:file] = nil unless args.key?(:file)
51
52
  @attributes.merge!(args)
52
53
  @new_record = new_record
53
54
  args.keys.each do |key|
@@ -16,6 +16,7 @@ module ActiveAdminImport
16
16
  :ignore,
17
17
  :template,
18
18
  :template_object,
19
+ :result_class,
19
20
  :resource_class,
20
21
  :resource_label,
21
22
  :plural_resource_label,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveAdminImport
4
- VERSION = '5.1.0'
4
+ VERSION = '6.0.0'
5
5
  end
@@ -0,0 +1,2 @@
1
+ Name,Last name,Birthday
2
+ John,Doe,1986-05-01
@@ -0,0 +1,3 @@
1
+ "Body"
2
+ "First comment"
3
+ "Second comment"
data/spec/import_spec.rb CHANGED
@@ -27,7 +27,7 @@ describe 'import', type: :feature do
27
27
  zip_file = File.expand_path("./spec/fixtures/files/#{name}.zip")
28
28
 
29
29
  begin
30
- Zip::File.open(zip_file, Zip::File::CREATE) do |z|
30
+ Zip::File.open(zip_file, create: true) do |z|
31
31
  z.add "#{name}.csv", File.expand_path("./spec/fixtures/files/#{name}.csv")
32
32
  end
33
33
  instance_eval &block
@@ -588,4 +588,147 @@ describe 'import', type: :feature do
588
588
  expect { add_author_resource(options) }.to raise_error(ArgumentError)
589
589
  end
590
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('Import').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
591
734
  end
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,7 @@
1
- # frozen_string_literal: true
2
- require 'coveralls'
3
- Coveralls.wear!
1
+ require 'simplecov'
2
+ SimpleCov.start do
3
+ add_filter '/spec/'
4
+ end
4
5
 
5
6
  $LOAD_PATH.unshift(File.dirname(__FILE__))
6
7
  $LOAD_PATH << File.expand_path('../support', __FILE__)
@@ -10,22 +11,18 @@ require 'bundler'
10
11
  Bundler.setup
11
12
 
12
13
  ENV['RAILS_ENV'] = 'test'
13
- # Ensure the Active Admin load path is happy
14
14
  require 'rails'
15
15
  ENV['RAILS'] = Rails.version
16
- ENV['RAILS_ROOT'] = File.expand_path("../rails/rails-#{ENV['RAILS']}", __FILE__)
17
- # Create the test app if it doesn't exists
16
+ ENV['DB'] ||= 'sqlite'
17
+ ENV['RAILS_ROOT'] = File.expand_path("../rails/rails-#{ENV['RAILS']}-#{ENV['DB']}", __FILE__)
18
18
  system 'rake setup' unless File.exist?(ENV['RAILS_ROOT'])
19
19
 
20
20
  require 'active_model'
21
- # require ActiveRecord to ensure that Ransack loads correctly
22
21
  require 'active_record'
23
22
  require 'action_view'
24
23
  require 'active_admin'
25
24
  ActiveAdmin.application.load_paths = [ENV['RAILS_ROOT'] + '/app/admin']
26
25
  require ENV['RAILS_ROOT'] + '/config/environment.rb'
27
- # Disabling authentication in specs so that we don't have to worry about
28
- # it allover the place
29
26
  ActiveAdmin.application.authentication_method = false
30
27
  ActiveAdmin.application.current_user_method = false
31
28
 
@@ -33,21 +30,20 @@ require 'rspec/rails'
33
30
  require 'support/admin'
34
31
  require 'capybara/rails'
35
32
  require 'capybara/rspec'
36
- require 'capybara/poltergeist'
33
+ require 'capybara/cuprite'
37
34
 
38
- Capybara.register_driver :poltergeist do |app|
39
- Capybara::Poltergeist::Driver.new(app, js_errors: true,
40
- timeout: 80,
41
- debug: true,
42
- phantomjs_options: ['--debug=no', '--load-images=no'])
35
+ Capybara.server = :webrick
36
+ Capybara.register_driver :cuprite do |app|
37
+ Capybara::Cuprite::Driver.new(app, headless: true, window_size: [1280, 800])
43
38
  end
44
-
45
- Capybara.javascript_driver = :poltergeist
39
+ Capybara.javascript_driver = :cuprite
40
+ Capybara.default_max_wait_time = 5
46
41
 
47
42
  RSpec.configure do |config|
48
43
  config.use_transactional_fixtures = false
49
44
 
50
45
  config.before(:suite) do
46
+ ActiveRecord::Migration.maintain_test_schema!
51
47
  DatabaseCleaner.strategy = :truncation
52
48
  DatabaseCleaner.clean_with(:truncation)
53
49
  end
@@ -8,8 +8,24 @@ def add_author_resource(options = {}, &block)
8
8
  end
9
9
 
10
10
  def add_post_resource(options = {}, &block)
11
+ cb = options.delete(:controller_block)
11
12
  ActiveAdmin.register Post do
12
13
  config.filters = false
14
+ controller(&cb) if cb
15
+ active_admin_import(options, &block)
16
+ end
17
+ Rails.application.reload_routes!
18
+ end
19
+
20
+ def add_nested_post_comment_resource(options = {}, &block)
21
+ cb = options.delete(:controller_block)
22
+ ActiveAdmin.register Post do
23
+ config.filters = false
24
+ end
25
+ ActiveAdmin.register PostComment do
26
+ config.filters = false
27
+ belongs_to :post
28
+ controller(&cb) if cb
13
29
  active_admin_import(options, &block)
14
30
  end
15
31
  Rails.application.reload_routes!
@@ -1,29 +1,60 @@
1
- # frozen_string_literal: true
2
- # Rails template to build the sample app for specs
1
+ create_file "app/assets/config/manifest.js", skip: true
2
+
3
+ db = ENV['DB'] || 'sqlite'
4
+ case db
5
+ when 'mysql'
6
+ remove_file 'config/database.yml'
7
+ create_file 'config/database.yml', <<~YAML
8
+ default: &default
9
+ adapter: mysql2
10
+ encoding: utf8mb4
11
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
12
+ host: <%= ENV.fetch("DB_HOST", "127.0.0.1") %>
13
+ port: <%= ENV.fetch("DB_PORT", 3306) %>
14
+ username: <%= ENV.fetch("DB_USERNAME", "root") %>
15
+ password: <%= ENV.fetch("DB_PASSWORD", "root") %>
16
+
17
+ test:
18
+ <<: *default
19
+ database: active_admin_import_test
20
+ YAML
21
+ when 'postgres', 'postgresql'
22
+ remove_file 'config/database.yml'
23
+ create_file 'config/database.yml', <<~YAML
24
+ default: &default
25
+ adapter: postgresql
26
+ encoding: unicode
27
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
28
+ host: <%= ENV.fetch("DB_HOST", "127.0.0.1") %>
29
+ port: <%= ENV.fetch("DB_PORT", 5432) %>
30
+ username: <%= ENV.fetch("DB_USERNAME", "postgres") %>
31
+ password: <%= ENV.fetch("DB_PASSWORD", "postgres") %>
32
+
33
+ test:
34
+ <<: *default
35
+ database: active_admin_import_test
36
+ YAML
37
+ end
38
+
39
+ generate :model, 'author name:string{10}:uniq last_name:string birthday:date --force'
40
+ generate :model, 'post title:string:uniq body:text request_ip:string author:references --force'
41
+ generate :model, 'post_comment body:text post:references --force'
3
42
 
4
- generate :model, 'author name:string{10}:uniq last_name:string birthday:date'
5
- generate :model, 'post title:string:uniq body:text author:references'
6
-
7
- # Add validation
8
43
  inject_into_file 'app/models/author.rb', " validates_presence_of :name\n validates_uniqueness_of :last_name\n", before: 'end'
9
- inject_into_file 'app/models/post.rb', " validates_presence_of :author\n", before: 'end'
10
-
11
- # Configure default_url_options in test environment
12
- inject_into_file 'config/environments/test.rb', " config.action_mailer.default_url_options = { :host => 'example.com' }\n", after: "config.cache_classes = true\n"
44
+ inject_into_file 'app/models/post.rb', " validates_presence_of :author\n has_many :post_comments\n", before: 'end'
13
45
 
14
- # Add our local Active Admin to the load path
15
- inject_into_file 'config/environment.rb', "\n$LOAD_PATH.unshift('#{File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib'))}')\nrequire \"active_admin\"\n", after: "require File.expand_path('../application', __FILE__)"
16
-
17
- run 'rm Gemfile'
46
+ # Add our local Active Admin to the load path (Rails 7.1+)
47
+ gsub_file "config/environment.rb",
48
+ 'require_relative "application"',
49
+ "require_relative \"application\"\n$LOAD_PATH.unshift('#{File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib'))}')\nrequire \"active_admin\"\n"
18
50
 
19
51
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
20
52
 
21
53
  generate :'active_admin:install --skip-users'
22
54
  generate :'formtastic:install'
23
55
 
24
- run 'rm -r test'
25
- run 'rm -r spec'
26
-
56
+ run 'rm -rf test'
27
57
  route "root :to => 'admin/dashboard#index'"
58
+ rake 'db:create db:migrate'
28
59
 
29
- rake 'db:migrate'
60
+ run 'rm -f Gemfile Gemfile.lock'
data/tasks/test.rake CHANGED
@@ -1,7 +1,21 @@
1
- # frozen_string_literal: true
2
- desc 'Creates a test rails app for the specs to run against'
1
+ desc "Creates a test rails app for the specs to run against"
3
2
  task :setup do
4
3
  require 'rails/version'
5
- system('mkdir spec/rails') unless File.exist?('spec/rails')
6
- system "bundle exec rails new spec/rails/rails-#{Rails::VERSION::STRING} -m spec/support/rails_template.rb --skip-spring --skip-turbolinks --skip-bootsnap"
4
+
5
+ db = ENV['DB'] || 'sqlite'
6
+ rails_db = case db
7
+ when 'mysql' then 'mysql'
8
+ when 'postgres', 'postgresql' then 'postgresql'
9
+ else 'sqlite3'
10
+ end
11
+
12
+ rails_new_opts = %W(
13
+ --skip-turbolinks
14
+ --skip-spring
15
+ --skip-bootsnap
16
+ -d #{rails_db}
17
+ -m
18
+ spec/support/rails_template.rb
19
+ )
20
+ system "bundle exec rails new spec/rails/rails-#{Rails::VERSION::STRING}-#{db} #{rails_new_opts.join(' ')}"
7
21
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_admin_import
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.0
4
+ version: 6.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Igor Fedoronchuk
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2023-11-02 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: activerecord-import
@@ -16,14 +15,14 @@ dependencies:
16
15
  requirements:
17
16
  - - ">="
18
17
  - !ruby/object:Gem::Version
19
- version: '0.27'
18
+ version: '2.0'
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - ">="
25
24
  - !ruby/object:Gem::Version
26
- version: '0.27'
25
+ version: '2.0'
27
26
  - !ruby/object:Gem::Dependency
28
27
  name: rchardet
29
28
  requirement: !ruby/object:Gem::Requirement
@@ -58,14 +57,20 @@ dependencies:
58
57
  requirements:
59
58
  - - ">="
60
59
  - !ruby/object:Gem::Version
61
- version: 1.0.0
60
+ version: '3.0'
61
+ - - "<"
62
+ - !ruby/object:Gem::Version
63
+ version: '4.0'
62
64
  type: :runtime
63
65
  prerelease: false
64
66
  version_requirements: !ruby/object:Gem::Requirement
65
67
  requirements:
66
68
  - - ">="
67
69
  - !ruby/object:Gem::Version
68
- version: 1.0.0
70
+ version: '3.0'
71
+ - - "<"
72
+ - !ruby/object:Gem::Version
73
+ version: '4.0'
69
74
  description: The most efficient way to import for Active Admin
70
75
  email:
71
76
  - fedoronchuk@gmail.com
@@ -76,7 +81,6 @@ files:
76
81
  - ".github/workflows/test.yml"
77
82
  - ".gitignore"
78
83
  - ".rubocop.yml"
79
- - CHANGELOG.md
80
84
  - Gemfile
81
85
  - LICENSE
82
86
  - README.md
@@ -108,6 +112,7 @@ files:
108
112
  - spec/fixtures/files/author.csv
109
113
  - spec/fixtures/files/author_broken_header.csv
110
114
  - spec/fixtures/files/author_invalid.csv
115
+ - spec/fixtures/files/author_invalid_format.txt
111
116
  - spec/fixtures/files/authors.csv
112
117
  - spec/fixtures/files/authors_bom.csv
113
118
  - spec/fixtures/files/authors_invalid_db.csv
@@ -120,6 +125,7 @@ files:
120
125
  - spec/fixtures/files/authors_with_tabs.tsv
121
126
  - spec/fixtures/files/empty.csv
122
127
  - spec/fixtures/files/only_headers.csv
128
+ - spec/fixtures/files/post_comments.csv
123
129
  - spec/fixtures/files/posts.csv
124
130
  - spec/fixtures/files/posts_for_author.csv
125
131
  - spec/fixtures/files/posts_for_author_no_headers.csv
@@ -131,11 +137,10 @@ files:
131
137
  - spec/support/admin.rb
132
138
  - spec/support/rails_template.rb
133
139
  - tasks/test.rake
134
- homepage: http://github.com/Fivell/active_admin_import
140
+ homepage: https://github.com/activeadmin-plugins/active_admin_import
135
141
  licenses:
136
142
  - MIT
137
143
  metadata: {}
138
- post_install_message:
139
144
  rdoc_options: []
140
145
  require_paths:
141
146
  - lib
@@ -143,41 +148,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
143
148
  requirements:
144
149
  - - ">="
145
150
  - !ruby/object:Gem::Version
146
- version: '0'
151
+ version: 3.1.0
147
152
  required_rubygems_version: !ruby/object:Gem::Requirement
148
153
  requirements:
149
154
  - - ">="
150
155
  - !ruby/object:Gem::Version
151
156
  version: '0'
152
157
  requirements: []
153
- rubyforge_project:
154
- rubygems_version: 2.7.6.2
155
- signing_key:
158
+ rubygems_version: 3.7.1
156
159
  specification_version: 4
157
160
  summary: ActiveAdmin import based on activerecord-import gem.
158
- test_files:
159
- - spec/fixtures/files/author.csv
160
- - spec/fixtures/files/author_broken_header.csv
161
- - spec/fixtures/files/author_invalid.csv
162
- - spec/fixtures/files/authors.csv
163
- - spec/fixtures/files/authors_bom.csv
164
- - spec/fixtures/files/authors_invalid_db.csv
165
- - spec/fixtures/files/authors_invalid_model.csv
166
- - spec/fixtures/files/authors_no_headers.csv
167
- - spec/fixtures/files/authors_values_exceeded_headers.csv
168
- - spec/fixtures/files/authors_win1251_win_endline.csv
169
- - spec/fixtures/files/authors_with_ids.csv
170
- - spec/fixtures/files/authors_with_semicolons.csv
171
- - spec/fixtures/files/authors_with_tabs.tsv
172
- - spec/fixtures/files/empty.csv
173
- - spec/fixtures/files/only_headers.csv
174
- - spec/fixtures/files/posts.csv
175
- - spec/fixtures/files/posts_for_author.csv
176
- - spec/fixtures/files/posts_for_author_no_headers.csv
177
- - spec/import_result_spec.rb
178
- - spec/import_spec.rb
179
- - spec/model_spec.rb
180
- - spec/spec_helper.rb
181
- - spec/support/active_model_lint.rb
182
- - spec/support/admin.rb
183
- - spec/support/rails_template.rb
161
+ test_files: []
data/CHANGELOG.md DELETED
@@ -1,33 +0,0 @@
1
- # Changelog
2
- ## [5.0.0] - 2021-11-16
3
- - Ruby 3 compatibility added #190 | @clinejj
4
- - Support for a non UTF-8 file when zip uploading #185| @naokirin
5
- - Rails 6 supported #183 | @pnghai
6
- - Drop ruby 2.4 support #192 | @Fivell
7
-
8
-
9
- ## [4.2.0] - 2020-02-05
10
- - generic exception for import added #175 | @linqueta
11
-
12
- ## [4.1.2] - 2019-12-16
13
- - allow application/octet-stream content-type #172 | @dmitry-sinina
14
- - Allow activerecord-import >= 0.27 #171 | @sagium
15
-
16
- ## [4.1.1] - 2019-09-20
17
- - Fix column slicing #168 | @doredesign
18
- - Handle errors on base #163
19
-
20
- ## [4.1.0] - 2019-01-15
21
- - Upgrade dependencies: `activerecord-import` to >=0.27.1 | @jkowens
22
-
23
- ## [4.0.0] - 2018-07-19
24
- - Adde German translation | @morris-frank
25
- - Remove support for Ruby 2.1 and Rails 4
26
-
27
- ## [3.1.0] - 2018-04-10
28
- - Lower dependency of ActiveAdmin to >= 1.0.0.pre2
29
- - Add possibility to skip columns/values in CSV (batch_slice_columns method)
30
-
31
- [Unreleased]: https://github.com/activeadmin-plugins/active_admin_import/compare/v4.0.0...HEAD
32
- [4.0.0]: https://github.com/activeadmin-plugins/active_admin_import/compare/v3.1.0...v4.0.0
33
- [3.1.0]: https://github.com/activeadmin-plugins/active_admin_import/compare/3.0.0...v3.1.0