active_admin_import 2.1.2 → 3.0.0.pre
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 +4 -4
- data/.hound.yml +4 -0
- data/.travis.yml +9 -0
- data/Gemfile +16 -0
- data/README.md +73 -173
- data/Rakefile +7 -2
- data/active_admin_import.gemspec +5 -3
- data/app/views/admin/import.html.erb +1 -1
- data/config/locales/en.yml +11 -4
- data/config/locales/es.yml +18 -0
- data/config/locales/it.yml +3 -1
- data/config/locales/zh-CN.yml +24 -0
- data/lib/active_admin_import/dsl.rb +39 -31
- data/lib/active_admin_import/import_result.rb +39 -0
- data/lib/active_admin_import/importer.rb +91 -44
- data/lib/active_admin_import/model.rb +80 -29
- data/lib/active_admin_import/options.rb +44 -0
- data/lib/active_admin_import/version.rb +1 -1
- data/lib/active_admin_import.rb +3 -0
- data/spec/fixtures/files/author.csv +2 -0
- data/spec/fixtures/files/author_broken_header.csv +2 -0
- data/spec/fixtures/files/author_invalid.csv +2 -0
- data/spec/fixtures/files/authors.csv +3 -0
- data/spec/fixtures/files/authors_bom.csv +3 -0
- data/spec/fixtures/files/authors_invalid_db.csv +3 -0
- data/spec/fixtures/files/authors_invalid_model.csv +3 -0
- data/spec/fixtures/files/authors_no_headers.csv +2 -0
- data/spec/fixtures/files/authors_win1251_win_endline.csv +3 -0
- data/spec/fixtures/files/authors_with_ids.csv +3 -0
- data/spec/fixtures/files/authors_with_semicolons.csv +3 -0
- data/spec/fixtures/files/empty.csv +0 -0
- data/spec/fixtures/files/only_headers.csv +1 -0
- data/spec/fixtures/files/posts.csv +4 -0
- data/spec/fixtures/files/posts_for_author.csv +3 -0
- data/spec/fixtures/files/posts_for_author_no_headers.csv +2 -0
- data/spec/import_result_spec.rb +32 -0
- data/spec/import_spec.rb +432 -0
- data/spec/model_spec.rb +5 -0
- data/spec/spec_helper.rb +72 -0
- data/spec/support/active_model_lint.rb +14 -0
- data/spec/support/admin.rb +20 -0
- data/spec/support/rails_template.rb +29 -0
- data/tasks/test.rake +6 -0
- metadata +80 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 46875662660bbc61d8dce4fa218234229d0c94d7
|
4
|
+
data.tar.gz: ba7347ef7348492d137e459e52a3430d5607f051
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 390733a4c6297317e6ab84c0528d05a65e93b422c1ac84961cd38f302a3f859d5303852a937dbf88762e599a8b5d4d845f8597cdcfc50a9ed3f43e1125d86192
|
7
|
+
data.tar.gz: 459e49db7a02bdca7c5fa53d9cad1b7b8e2937ff2e223b479ee7551a8cd9b7e6993f5b4968c1a5c86e33f206467075afd9d7c7bb7c868906f4af050cae2b2754
|
data/.hound.yml
ADDED
data/.travis.yml
ADDED
data/Gemfile
CHANGED
@@ -2,3 +2,19 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
# Specify your gem's dependencies in active_admin_importable.gemspec
|
4
4
|
gemspec
|
5
|
+
group :test do
|
6
|
+
gem 'rails', '4.1.9'
|
7
|
+
gem 'rspec-rails'
|
8
|
+
gem 'activeadmin', github: 'activeadmin' , ref: '54bede0558a99ab759f98f9b24e1b0144063a81e'
|
9
|
+
|
10
|
+
gem 'coveralls', require: false # Test coverage website. Go to https://coveralls.io
|
11
|
+
|
12
|
+
gem 'devise'
|
13
|
+
gem 'sass-rails'
|
14
|
+
gem 'sqlite3'
|
15
|
+
gem 'launchy'
|
16
|
+
gem 'database_cleaner'
|
17
|
+
gem 'capybara'
|
18
|
+
gem 'selenium-webdriver'
|
19
|
+
gem 'poltergeist'
|
20
|
+
end
|
data/README.md
CHANGED
@@ -1,9 +1,18 @@
|
|
1
1
|
# ActiveAdminImport
|
2
|
-
The most fastest and efficient CSV import for Active Admin
|
3
|
-
with support of validations
|
2
|
+
[The most fastest and efficient CSV import for Active Admin
|
3
|
+
with support of validations, bulk inserts and encodings handling](http://activeadmin-plugins.github.io/active_admin_import/)
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
[](https://travis-ci.org/activeadmin-pluginsl/active_admin_import)
|
8
|
+
[](https://gemnasium.com/activeadmin-plugins/active_admin_import)
|
9
|
+
[](https://coveralls.io/r/activeadmin-plugins/active_admin_import)
|
4
10
|
|
11
|
+
[](https://codeclimate.com/github/activeadmin-plugins/active_admin_import)
|
12
|
+
[](https://rubygems.org/gems/active_admin_import)
|
13
|
+
[](http://Fivell.mit-license.org)
|
5
14
|
|
6
|
-
|
15
|
+
master can be used with AA 1.0.0 and Rails >= 4.1
|
7
16
|
|
8
17
|
|
9
18
|
#Installation
|
@@ -11,203 +20,94 @@ Should work with both AA 0.6 and 1.0.0
|
|
11
20
|
Add this line to your application's Gemfile:
|
12
21
|
|
13
22
|
```ruby
|
14
|
-
gem "active_admin_import" , '2.1.
|
15
|
-
```
|
16
|
-
|
17
|
-
And then execute:
|
18
|
-
|
19
|
-
$ bundle
|
20
|
-
|
21
|
-
|
23
|
+
gem "active_admin_import" , '2.1.2'
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
-
"Because plain-vanilla, out-of-the-box ActiveRecord doesn’t provide support for inserting large amounts of data efficiently"
|
26
|
-
|
27
|
-
cool features of activerecord-import
|
28
|
-
|
29
|
-
activerecord-import can perform validations (fast)
|
30
|
-
activerecord-import can perform on duplicate key updates (requires mysql)
|
31
|
-
|
32
|
-
|
33
|
-
So active_admin_import features
|
25
|
+
```
|
26
|
+
or
|
34
27
|
|
35
|
-
|
36
|
-
|
37
|
-
CSV options
|
38
|
-
Ability to prepend CSV headers automatically
|
39
|
-
Bulk import (activerecord-import)
|
40
|
-
Ability to customize template
|
41
|
-
Callbacks support
|
42
|
-
Zip files import
|
43
|
-
and more ....
|
28
|
+
```ruby
|
29
|
+
gem "active_admin_import" , github: "activeadmin-plugins/active_admin_import"
|
44
30
|
|
45
|
-
|
31
|
+
```
|
46
32
|
|
47
|
-
|
48
|
-
# +csv_options+:: hash with column separator, row separator, etc
|
49
|
-
# +validate+:: true|false, means perfoem validations or not
|
50
|
-
# +batch_size+:: integer value of max record count inserted by 1 query/transaction
|
51
|
-
# +before_import+:: proc for before import action, hook called with importer object
|
52
|
-
# +after_import+:: proc for after import action, hook called with importer object
|
53
|
-
# +before_batch_import+:: proc for before each batch action, called with importer object
|
54
|
-
# +after_batch_import+:: proc for after each batch action, called with importer object
|
55
|
-
# +on_duplicate_key_update+:: an Array or Hash, tells activerecord-import to use MySQL's ON DUPLICATE KEY UPDATE ability.
|
56
|
-
# +timestamps+:: true|false, tells activerecord-import to not add timestamps (if false) even if record timestamps is disabled in ActiveRecord::Base
|
57
|
-
# +ignore+:: true|false, tells activerecord-import toto use MySQL's INSERT IGNORE ability
|
58
|
-
# +params_keys+:: params values available in callbacks
|
59
|
-
# +template+:: custom template rendering
|
60
|
-
# +template_object+:: object passing to view
|
61
|
-
# +locals+:: local variables for template
|
62
|
-
# +resource_class+:: resource class name
|
63
|
-
# +resource_label+:: resource label value
|
64
|
-
# +headers_rewrites+:: hash with key (csv header) - value (db column name) rows mapping
|
33
|
+
And then execute:
|
65
34
|
|
35
|
+
$ bundle
|
66
36
|
|
67
37
|
|
68
|
-
|
38
|
+
# active_admin_import features
|
39
|
+
<ol>
|
40
|
+
<li> Replacements/Updates support</li>
|
41
|
+
<li> Encoding handling</li>
|
42
|
+
<li> CSV options</li>
|
43
|
+
<li> Ability to describe/change CSV headers</li>
|
44
|
+
<li> Bulk import (activerecord-import)</li>
|
45
|
+
<li> Callbacks</li>
|
46
|
+
<li> Zip files</li>
|
47
|
+
<li> and more...</li>
|
48
|
+
</ol>
|
69
49
|
|
70
|
-
|
71
|
-
back: {action: :import},
|
72
|
-
csv_options: {},
|
73
|
-
template: "admin/import",
|
74
|
-
fetch_extra_options_from_params: [],
|
75
|
-
resource_class: config.resource_class,
|
76
|
-
resource_label: config.resource_label,
|
77
|
-
plural_resource_label: config.plural_resource_label,
|
78
|
-
```
|
50
|
+
|
79
51
|
|
80
|
-
|
52
|
+
#### Basic usage
|
81
53
|
|
82
|
-
```ruby
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
:before_import => proc{ Post.delete_all},
|
87
|
-
:batch_size => 1000
|
88
|
-
|
89
|
-
|
90
|
-
end
|
54
|
+
```ruby
|
55
|
+
ActiveAdmin.register Post
|
56
|
+
active_admin_import options
|
57
|
+
end
|
91
58
|
```
|
92
59
|
|
93
60
|
|
94
|
-
|
95
|
-
|
96
|
-
|
61
|
+
#### Options
|
62
|
+
Tool | Description
|
63
|
+
--------------------- | -----------
|
64
|
+
:back |resource action to redirect after processing
|
65
|
+
:csv_options |hash with column separator, row separator, etc
|
66
|
+
:validate |bool means perform validations or not
|
67
|
+
: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
|
69
|
+
:before_import |proc for before import action, hook called with importer object
|
70
|
+
:after_import |proc for after import action, hook called with importer object
|
71
|
+
:before_batch_import |proc for before each batch action, called with importer object
|
72
|
+
:after_batch_import |proc for after each batch action, called with importer object
|
73
|
+
:on_duplicate_key_update|an Array or Hash, tells activerecord-import to use MySQL's ON DUPLICATE KEY UPDATE ability.
|
74
|
+
:timestamps |bool, tells activerecord-import to not add timestamps (if false) even if record timestamps is disabled in ActiveRecord::Base
|
75
|
+
:ignore |bool, tells activerecord-import toto use MySQL's INSERT IGNORE ability
|
76
|
+
:template |custom template rendering
|
77
|
+
:template_object |object passing to view
|
78
|
+
:resource_class |resource class name
|
79
|
+
:resource_label |resource label value
|
80
|
+
:plural_resource_label |pluralized resource label value (default config.plural_resource_label)
|
81
|
+
:headers_rewrites |hash with key (csv header) - value (db column name) rows mapping
|
97
82
|
|
98
|
-
```ruby
|
99
|
-
ActiveAdmin.register Post do
|
100
|
-
active_admin_import :validate => false,
|
101
|
-
:csv_options => {:col_sep => ";" },
|
102
|
-
:resource_class => ImportedPost , # we import data into another resource
|
103
|
-
:before_import => proc{ ImportedPost.delete_all },
|
104
|
-
:after_import => proc{
|
105
|
-
Post.transaction do
|
106
|
-
Post.delete_all
|
107
|
-
Post.connection.execute("INSERT INTO posts (SELECT * FROM import_posts)")
|
108
|
-
end
|
109
|
-
},
|
110
|
-
:back => proc { config.namespace.resource_for(Post).route_collection_path } # redirect to post index
|
111
|
-
end
|
112
|
-
```
|
113
83
|
|
114
84
|
|
115
|
-
|
116
|
-
|
117
|
-
```ruby
|
118
|
-
ActiveAdmin.register Post do
|
119
|
-
active_admin_import :validate => true,
|
120
|
-
:template_object => ActiveAdminImport::Model.new(
|
121
|
-
:hint => "file will be imported with such header format: 'body','title','author'",
|
122
|
-
:csv_headers => ["body","title","author"]
|
123
|
-
)
|
124
|
-
end
|
125
|
-
```
|
126
|
-
|
127
|
-
Example4 Importing without forcing to UTF-8 and disallow archives
|
85
|
+
#### Wiki
|
128
86
|
|
87
|
+
[Check various examples](https://github.com/activeadmin-plugins/active_admin_import/wiki)
|
129
88
|
|
130
|
-
|
131
|
-
ActiveAdmin.register Post do
|
132
|
-
active_admin_import :validate => true,
|
133
|
-
:template_object => ActiveAdminImport::Model.new(
|
134
|
-
:hint => "file will be encoded to ISO-8859-1",
|
135
|
-
:force_encoding => "ISO-8859-1",
|
136
|
-
:allow_archive => false
|
137
|
-
)
|
138
|
-
end
|
139
|
-
```
|
89
|
+
## Dependencies
|
140
90
|
|
91
|
+
Tool | Description
|
92
|
+
--------------------- | -----------
|
93
|
+
[rchardet] | Character encoding auto-detection in Ruby. As smart as your browser. Open source.
|
94
|
+
[activerecord-import] | Powerful library for bulk inserting data using ActiveRecord.
|
141
95
|
|
142
|
-
|
96
|
+
[rchardet]: https://github.com/jmhodges/rchardet
|
97
|
+
[activerecord-import]: https://github.com/zdennis/activerecord-import
|
143
98
|
|
144
99
|
|
145
|
-
|
146
|
-
ActiveAdmin.register Post do
|
147
|
-
active_admin_import :validate => true,
|
148
|
-
:before_batch_import => proc { |import|
|
149
|
-
import.file #current file used
|
150
|
-
import.resource #ActiveRecord class to import to
|
151
|
-
import.options # options
|
152
|
-
import.result # result before bulk iteration
|
153
|
-
import.headers # CSV headers
|
154
|
-
import.csv_lines #lines to import
|
155
|
-
import.model #template_object instance
|
156
|
-
},
|
157
|
-
:after_batch_import => proc{ |import|
|
158
|
-
#the same
|
159
|
-
}
|
160
|
-
end
|
161
|
-
```
|
162
|
-
|
163
|
-
Example6 dynamic CSV options, template overriding
|
164
|
-
|
165
|
-
1) put overrided template to app/views/import.html.erb
|
166
|
-
|
167
|
-
```erb
|
168
|
-
|
169
|
-
<p>
|
170
|
-
<%= raw(@active_admin_import_model.hint) %>
|
171
|
-
</p>
|
172
|
-
<%= semantic_form_for @active_admin_import_model, url: {action: :do_import}, html: {multipart: true} do |f| %>
|
173
|
-
<%= f.inputs do %>
|
174
|
-
<%= f.input :file, as: :file %>
|
175
|
-
<% end %>
|
176
|
-
<%= f.inputs "CSV options", :for => [:csv_options, OpenStruct.new(@active_admin_import_model.csv_options)] do |csv| %>
|
177
|
-
<% csv.with_options :input_html => {:style => 'width:40px;'} do |opts| %>
|
178
|
-
<%= opts.input :col_sep %>
|
179
|
-
<%= opts.input :row_sep %>
|
180
|
-
<%= opts.input :quote_char %>
|
181
|
-
<% end %>
|
182
|
-
<% end %>
|
183
|
-
|
184
|
-
<%= f.actions do %>
|
185
|
-
<%= f.action :submit, label: t("active_admin_import.import_btn"), button_html: {disable_with: t("active_admin_import.import_btn_disabled")} %>
|
186
|
-
<% end %>
|
187
|
-
<% end %>
|
188
|
-
|
189
|
-
```
|
100
|
+
## Contributing
|
190
101
|
|
191
|
-
|
102
|
+
1. Fork it
|
103
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
104
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
105
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
106
|
+
5. Create new Pull Request
|
192
107
|
|
193
|
-
```ruby
|
194
|
-
ActiveAdmin.register Post do
|
195
|
-
active_admin_import :validate => false,
|
196
|
-
:template => 'import' ,
|
197
|
-
:template_object => ActiveAdminImport::Model.new(
|
198
|
-
:hint => "specify CSV options"
|
199
|
-
:csv_options => {:col_sep => ";", :row_sep => nil, :quote_char => nil}
|
200
|
-
)
|
201
|
-
end
|
202
|
-
```
|
203
108
|
|
204
|
-
#Links
|
205
|
-
https://github.com/gregbell/active_admin
|
206
109
|
|
207
|
-
https://github.com/zdennis/activerecord-import
|
208
110
|
|
209
|
-
#Source Doc
|
210
|
-
http://rubydoc.info/gems/active_admin_import/2.1.1/
|
211
111
|
|
212
112
|
|
213
113
|
|
data/Rakefile
CHANGED
data/active_admin_import.gemspec
CHANGED
@@ -15,9 +15,11 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.require_paths = ["lib"]
|
16
16
|
gem.version = ActiveAdminImport::VERSION
|
17
17
|
|
18
|
-
gem.add_runtime_dependency 'activerecord-import', '~> 0.4', '>= 0.4.1'
|
19
|
-
gem.add_runtime_dependency 'activeadmin', '>= 0.6.0'
|
20
|
-
gem.add_runtime_dependency 'rubyzip', '~> 1.0', '>= 1.0.0'
|
21
18
|
|
19
|
+
gem.add_runtime_dependency 'activerecord-import', '~> 0.8.0'
|
20
|
+
gem.add_runtime_dependency 'rchardet', '~> 1.5'
|
21
|
+
|
22
|
+
gem.add_runtime_dependency 'rubyzip', '~> 1.0', '>= 1.0.0'
|
23
|
+
gem.add_dependency "rails", ">= 4.0"
|
22
24
|
|
23
25
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
<%= raw(@active_admin_import_model.hint) %>
|
3
3
|
</p>
|
4
4
|
<%= semantic_form_for @active_admin_import_model, url: {action: :do_import}, html: {multipart: true} do |f| %>
|
5
|
-
<%= f.inputs do %>
|
5
|
+
<%= f.inputs name: t("active_admin_import.details") do %>
|
6
6
|
<%= f.input :file, as: :file %>
|
7
7
|
<% end %>
|
8
8
|
<%= f.actions do %>
|
data/config/locales/en.yml
CHANGED
@@ -2,15 +2,22 @@ en:
|
|
2
2
|
active_admin:
|
3
3
|
import: "Import"
|
4
4
|
active_admin_import:
|
5
|
+
file: 'File'
|
6
|
+
file_error: "Error: %{message}"
|
5
7
|
file_format_error: "You can import only valid csv file"
|
6
8
|
file_empty_error: "You can't import empty file"
|
7
9
|
no_file_error: "Please, select file to import"
|
10
|
+
details: "Please, select file to import"
|
8
11
|
imported:
|
9
12
|
one: "Successfully imported 1 %{model}"
|
10
13
|
other: "Successfully imported %{count} %{plural_model}"
|
11
14
|
failed:
|
12
|
-
one: "Failed to import 1 %{model}"
|
13
|
-
other: "Failed to import %{count} %{plural_model}"
|
14
|
-
import_model: "Import %{
|
15
|
+
one: "Failed to import 1 %{model}: %{message}"
|
16
|
+
other: "Failed to import %{count} %{plural_model}: %{message}"
|
17
|
+
import_model: "Import %{plural_model}"
|
15
18
|
import_btn: "Import"
|
16
|
-
import_btn_disabled: "Wait..."
|
19
|
+
import_btn_disabled: "Wait..."
|
20
|
+
csv_options: "CSV options"
|
21
|
+
col_sep: 'Col sep'
|
22
|
+
row_sep: 'Row sep'
|
23
|
+
quote_char: 'Quote char'
|
@@ -0,0 +1,18 @@
|
|
1
|
+
es:
|
2
|
+
active_admin:
|
3
|
+
import: "Importar"
|
4
|
+
active_admin_import:
|
5
|
+
file_error: "Error: %{message}"
|
6
|
+
file_format_error: "Sólo se puede importar un archivo CSV válido"
|
7
|
+
file_empty_error: "No puedes importar un archivo vacío"
|
8
|
+
no_file_error: "Seleccione un archivo para importar"
|
9
|
+
details: "Seleccione un archivo"
|
10
|
+
imported:
|
11
|
+
one: "Se ha importado exitosamente 1 %{model}"
|
12
|
+
other: "Se ha importado exitosamente %{count} %{plural_model}"
|
13
|
+
failed:
|
14
|
+
one: "No se pudo importar 1 %{model}"
|
15
|
+
other: "No se pudo importar %{count} %{plural_model}"
|
16
|
+
import_model: "Importar %{plural_model}"
|
17
|
+
import_btn: "Importar"
|
18
|
+
import_btn_disabled: "Espere..."
|
data/config/locales/it.yml
CHANGED
@@ -2,15 +2,17 @@ it:
|
|
2
2
|
active_admin:
|
3
3
|
import: "Importa"
|
4
4
|
active_admin_import:
|
5
|
+
file_error: "Errore: %{message}"
|
5
6
|
file_format_error: "Puoi importare solo CSV conformi"
|
6
7
|
no_file_error: "Per favore, seleziona un file da importare"
|
7
8
|
file_empty_error: "Non è possibile importare file vuoto"
|
9
|
+
details: "Per favore, seleziona un file da importare"
|
8
10
|
imported:
|
9
11
|
one: "Importato 1 %{model} con successo"
|
10
12
|
other: "Importati %{count} %{plural_model} con successo"
|
11
13
|
failed:
|
12
14
|
one: "Importazione di 1 %{model} fallita"
|
13
15
|
other: "Importazione di %{count} %{plural_model} fallita"
|
14
|
-
import_model: "Importa %{
|
16
|
+
import_model: "Importa %{plural_model}"
|
15
17
|
import_btn: "Importa"
|
16
18
|
import_btn_disabled: "In attesa..."
|
@@ -0,0 +1,24 @@
|
|
1
|
+
zh-CN:
|
2
|
+
active_admin:
|
3
|
+
import: "导入"
|
4
|
+
do_import: "导入"
|
5
|
+
active_admin_import:
|
6
|
+
file: '文件'
|
7
|
+
file_error: "导入错误: %{message}"
|
8
|
+
file_format_error: "请您上传 CSV 格式的文件"
|
9
|
+
file_empty_error: "您上传的文件为空"
|
10
|
+
no_file_error: "请您选择要上传的文件"
|
11
|
+
details: "请您选择要上传的文件"
|
12
|
+
imported:
|
13
|
+
one: "成功导入 1 份%{model}"
|
14
|
+
other: "成功导入 %{count} 份%{plural_model}"
|
15
|
+
failed:
|
16
|
+
one: "未能导入 1 份%{model}: %{message}"
|
17
|
+
other: "未能导入 %{count} 份%{plural_model}: %{message}"
|
18
|
+
import_model: "导入%{plural_model}"
|
19
|
+
import_btn: "导入"
|
20
|
+
import_btn_disabled: "请稍等..."
|
21
|
+
csv_options: "选项"
|
22
|
+
col_sep: '列分隔符'
|
23
|
+
row_sep: '行分隔符'
|
24
|
+
quote_char: '引用字符'
|
@@ -1,18 +1,19 @@
|
|
1
1
|
module ActiveAdminImport
|
2
2
|
module DSL
|
3
|
+
|
4
|
+
|
3
5
|
# Declares import functionality
|
4
6
|
#
|
5
7
|
# Options
|
6
8
|
# +back+:: resource action to redirect after processing
|
7
|
-
# +col_sep+:: column separator used for CSV parsing (deprecated)
|
8
|
-
# +row_sep+:: column separator used for CSV parsing (deprecated)
|
9
9
|
# +csv_options+:: hash to override default CSV options
|
10
|
-
# +validate+:: true|false, means perfoem validations or not
|
11
10
|
# +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
|
12
12
|
# +before_import+:: proc for before import action, hook called with importer object
|
13
13
|
# +after_import+:: proc for after import action, hook called with importer object
|
14
14
|
# +before_batch_import+:: proc for before each batch action, called with importer object
|
15
15
|
# +after_batch_import+:: proc for after each batch action, called with importer object
|
16
|
+
# +validate+:: true|false, means perform validations or not
|
16
17
|
# +on_duplicate_key_update+:: an Array or Hash, tells activerecord-import to use MySQL's ON DUPLICATE KEY UPDATE ability.
|
17
18
|
# +timestamps+:: true|false, tells activerecord-import to not add timestamps (if false) even if record timestamps is disabled in ActiveRecord::Base
|
18
19
|
# +ignore+:: true|false, tells activerecord-import to use MySQL's INSERT IGNORE ability
|
@@ -20,58 +21,65 @@ module ActiveAdminImport
|
|
20
21
|
# +template_object+:: object passing to view
|
21
22
|
# +resource_class+:: resource class name, override to import to another table (default config.resource_class)
|
22
23
|
# +resource_label+:: resource label value (default config.resource_label)
|
23
|
-
# +plural_resource_label+::
|
24
|
+
# +plural_resource_label+:: pluralized resource label value (default config.plural_resource_label)
|
24
25
|
#
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
26
|
+
|
27
|
+
|
28
|
+
DEFAULT_RESULT_PROC = ->(result, options) do
|
29
|
+
|
30
|
+
model_name = options[:resource_label].downcase
|
31
|
+
plural_model_name = options[:plural_resource_label].downcase
|
32
|
+
if result.empty?
|
33
|
+
flash[:warning] = I18n.t('active_admin_import.file_empty_error')
|
34
|
+
else
|
35
|
+
if result.has_failed?
|
36
|
+
flash[:error] = I18n.t('active_admin_import.failed', count: result.failed.count, model: model_name, plural_model: plural_model_name, message: result.failed_message(limit: 5))
|
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)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
def active_admin_import(options = {}, &block)
|
47
|
+
options.assert_valid_keys(*Options::VALID_OPTIONS)
|
48
|
+
|
49
|
+
options = Options.options_for(config, options)
|
50
|
+
params_key = ActiveModel::Naming.param_key(options[:template_object])
|
37
51
|
|
38
52
|
collection_action :import, method: :get do
|
39
53
|
authorize!(ActiveAdminImport::Auth::IMPORT, active_admin_config.resource_class)
|
40
|
-
|
41
|
-
@active_admin_import_model = options[:template_object] || ActiveAdminImport::Model.new
|
54
|
+
@active_admin_import_model = options[:template_object]
|
42
55
|
render template: options[:template]
|
43
56
|
end
|
44
57
|
|
45
58
|
action_item :import, only: :index do
|
46
59
|
if authorized?(ActiveAdminImport::Auth::IMPORT, active_admin_config.resource_class)
|
47
|
-
link_to(I18n.t('active_admin_import.import_model',
|
60
|
+
link_to(I18n.t('active_admin_import.import_model', plural_model: options[:plural_resource_label]), action: :import)
|
48
61
|
end
|
49
62
|
end
|
50
63
|
|
51
64
|
collection_action :do_import, method: :post do
|
52
65
|
authorize!(ActiveAdminImport::Auth::IMPORT, active_admin_config.resource_class)
|
53
66
|
|
54
|
-
@active_admin_import_model = options[:template_object]
|
67
|
+
@active_admin_import_model = options[:template_object]
|
55
68
|
@active_admin_import_model.assign_attributes(params[params_key].try(:deep_symbolize_keys) || {})
|
56
69
|
#go back to form
|
57
70
|
return render template: options[:template] unless @active_admin_import_model.valid?
|
58
71
|
@importer = Importer.new(options[:resource_class], @active_admin_import_model, options)
|
59
72
|
begin
|
60
|
-
@importer.import
|
73
|
+
result = @importer.import
|
74
|
+
|
61
75
|
if block_given?
|
62
76
|
instance_eval &block
|
63
77
|
else
|
64
|
-
|
65
|
-
plural_model_name = options[:plural_resource_label].downcase
|
66
|
-
if @importer.result[:imported].to_i > 0
|
67
|
-
flash[:notice] = I18n.t('active_admin_import.imported', count: @importer.result[:imported].to_i, model: model_name, plural_model: plural_model_name)
|
68
|
-
end
|
69
|
-
if @importer.result[:failed].count > 0
|
70
|
-
flash[:error] = I18n.t('active_admin_import.failed', count: @importer.result[:failed].count, model: model_name, plural_model: plural_model_name)
|
71
|
-
end
|
78
|
+
instance_exec result, options, &DEFAULT_RESULT_PROC
|
72
79
|
end
|
73
|
-
rescue ActiveRecord::Import::MissingColumnError, NoMethodError => e
|
74
|
-
|
80
|
+
rescue ActiveRecord::Import::MissingColumnError, NoMethodError, ActiveRecord::StatementInvalid => e
|
81
|
+
Rails.logger.error(I18n.t('active_admin_import.file_error', message: e.message))
|
82
|
+
flash[:error] = I18n.t('active_admin_import.file_error', message: e.message[0..200])
|
75
83
|
end
|
76
84
|
redirect_to options[:back]
|
77
85
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module ActiveAdminImport
|
2
|
+
class ImportResult
|
3
|
+
attr_reader :failed, :total
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@failed = []
|
7
|
+
@total = 0
|
8
|
+
end
|
9
|
+
|
10
|
+
def add(result, qty)
|
11
|
+
@failed += result.failed_instances
|
12
|
+
@total += qty
|
13
|
+
end
|
14
|
+
|
15
|
+
def imported_qty
|
16
|
+
total - failed.count
|
17
|
+
end
|
18
|
+
|
19
|
+
def has_imported?
|
20
|
+
imported_qty > 0
|
21
|
+
end
|
22
|
+
|
23
|
+
def has_failed?
|
24
|
+
@failed.any?
|
25
|
+
end
|
26
|
+
|
27
|
+
def empty?
|
28
|
+
total == 0
|
29
|
+
end
|
30
|
+
|
31
|
+
def failed_message(options = {})
|
32
|
+
limit = options.fetch(:limit, failed.count)
|
33
|
+
failed.first(limit).map{|record|
|
34
|
+
errors = record.errors
|
35
|
+
(errors.full_messages.zip errors.keys.map{|k| record.send k}).map{|ms| ms.join(' - ')}.join(', ')
|
36
|
+
}.join(" ; ")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|