rails_admin_import 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -1
- data/README.md +24 -7
- data/Rakefile +2 -2
- data/app/views/rails_admin/main/import.html.haml +1 -7
- data/lib/rails_admin_import/action.rb +2 -1
- data/lib/rails_admin_import/config.rb +6 -1
- data/lib/rails_admin_import/eager_load.rb +3 -0
- data/lib/rails_admin_import/formats.rb +6 -0
- data/lib/rails_admin_import/formats/csv_importer.rb +2 -6
- data/lib/rails_admin_import/formats/xlsx_importer.rb +48 -0
- data/lib/rails_admin_import/import_model.rb +17 -7
- data/lib/rails_admin_import/importer.rb +6 -6
- data/lib/rails_admin_import/version.rb +1 -1
- metadata +32 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d22596961dbc1568f035e4f5c6e5896fcfb01474
|
4
|
+
data.tar.gz: 407a068d2bf2d62e096ec46c4c061b559db98bec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d1d2338cbf97015e11c114b1ee6d68994c8517942497ce839f029ac02e36d133f8bd9866634e23e5e2825d9a88033c25e5508016a209f39d48d593edcf2c376f
|
7
|
+
data.tar.gz: 82fa136b73f126c8dcabaa7e83e472b0815b0231286d505be16718c15a7b8f9aa425fee723e67424419dd5e94a51182adbd6133238f4382b2d4f36df5ce96f80
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## [1.2.0] - 2015-08-27
|
4
|
+
### Changed
|
5
|
+
- Existing records can now be updated based on a belongs_to foreign key. Thanks Diego Carrion!
|
6
|
+
- Add Excel file format support
|
7
|
+
- Autoload the Excel import and encoding detection gems
|
8
|
+
|
3
9
|
## [1.1.0] - 2015-08-04
|
4
10
|
### Changed
|
5
11
|
- `csv_options` config added. Thanks Maksim Burnin!
|
@@ -23,4 +29,4 @@ Major rework of the gem by new maintainer.
|
|
23
29
|
- Updated/corrected README
|
24
30
|
- Merged ImportLogger work
|
25
31
|
- Merged modifications to import view
|
26
|
-
- Merged post save hook on models
|
32
|
+
- Merged post save hook on models
|
data/README.md
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
|
3
3
|
[![Build Status](https://travis-ci.org/monkbroc/rails_admin_import.svg?branch=master)](https://travis-ci.org/monkbroc/rails_admin_import)
|
4
4
|
|
5
|
-
Plugin functionality to add generic import to Rails Admin from CSV and
|
5
|
+
Plugin functionality to add generic import to Rails Admin from CSV, JSON and XLSX files
|
6
6
|
|
7
|
-
*This Readme is for version 1.
|
7
|
+
*This Readme is for version 1.x. If you are still using version 0.1.x, see [this branch](https://github.com/stephskardal/rails_admin_import/tree/legacy)*
|
8
8
|
|
9
9
|
## Installation
|
10
10
|
|
11
11
|
* First, add to Gemfile:
|
12
12
|
|
13
13
|
```
|
14
|
-
gem "rails_admin_import", "~> 1.
|
14
|
+
gem "rails_admin_import", "~> 1.2"
|
15
15
|
```
|
16
16
|
|
17
17
|
* Define configuration in `config/initializers/rails_admin_import.rb`:
|
@@ -52,6 +52,8 @@ can :import, [User, Model1, Model2]
|
|
52
52
|
|
53
53
|
## File format
|
54
54
|
|
55
|
+
The format is inferred by the extension (.csv, .json or .xlsx).
|
56
|
+
|
55
57
|
### CSV
|
56
58
|
|
57
59
|
The first line must contain attribute names. They will be converted to lowercase and underscored (First Name ==> first_name).
|
@@ -72,6 +74,11 @@ Michael,Bolton,IT,
|
|
72
74
|
|
73
75
|
The file must be an array or an object with a root key the same name as the plural model name, i.e. the default Rails JSON output format with include_root_in_json on or off.
|
74
76
|
|
77
|
+
### XLSX
|
78
|
+
|
79
|
+
The Microsoft Excel XLM format (XLSX) is supported, but not the old binary Microsoft Excel format (XLS).
|
80
|
+
|
81
|
+
The expected rows and columns are the same as for the CSV format (first line contains headers, multiple columns for "many" associations).
|
75
82
|
|
76
83
|
## Configuration
|
77
84
|
|
@@ -83,7 +90,7 @@ The file must be an array or an object with a root key the same name as the plur
|
|
83
90
|
|
84
91
|
* __rollback_on_error__ (default `false`): import records in a transaction and rollback if there is one error. Only for ActiveRecord, not Mongoid.
|
85
92
|
|
86
|
-
* __header_converter__ (default `
|
93
|
+
* __header_converter__ (default `lambda { ... }`): a lambda to convert each CSV header text string to a model attribute name. The default header converter converts to lowercase and replaces spaces with underscores.
|
87
94
|
|
88
95
|
* __csv_options__ (default `{}`): a hash of options that will be passed to a new [CSV](http://ruby-doc.org/stdlib-2.0.0/libdoc/csv/rdoc/CSV.html) instance
|
89
96
|
|
@@ -175,6 +182,16 @@ The gem is tested to work with ActiveRecord and Mongoid.
|
|
175
182
|
Support for Mongoid is early, so if you can suggest improvements (especially around importing embedded models), open an issue.
|
176
183
|
|
177
184
|
|
185
|
+
## Eager loading
|
186
|
+
|
187
|
+
Since the import functionality is rarely used in many applications, some gems are autoloaded when first used during an import in order to save memory at boot.
|
188
|
+
|
189
|
+
If you prefer to eager load all dependecies at boot, use this line in your `Gemfile`.
|
190
|
+
|
191
|
+
```
|
192
|
+
gem "rails_admin_import", "~> 1.2.0", require: "rails_admin_import/eager_load"
|
193
|
+
```
|
194
|
+
|
178
195
|
## Upgrading
|
179
196
|
|
180
197
|
* Move global config to `config.configure_with(:import)` in `config/initializers/rails_admin_import.rb`.
|
@@ -194,7 +211,7 @@ Support for Mongoid is early, so if you can suggest improvements (especially aro
|
|
194
211
|
git clone https://github.com/stephskardal/rails_admin_import
|
195
212
|
|
196
213
|
2. Run `bundle install`
|
197
|
-
3. Run `rspec`
|
214
|
+
3. Run `bundle exec rspec`
|
198
215
|
|
199
216
|
The structure of the tests is taken from the Rails Admin gem.
|
200
217
|
|
@@ -209,8 +226,8 @@ Maintainer (since May 2015): [Julien Vanier](https://github.com/monkbroc)
|
|
209
226
|
|
210
227
|
Everyone is encouraged to help improve this project. Here are a few ways you can help:
|
211
228
|
|
212
|
-
- [Report bugs](https://github.com/
|
213
|
-
- Fix bugs and [submit pull requests](https://github.com/
|
229
|
+
- [Report bugs](https://github.com/stephskardal/rails_admin_import/issues)
|
230
|
+
- Fix bugs and [submit pull requests](https://github.com/stephskardal/rails_admin_import/pulls)
|
214
231
|
- Write, clarify, or fix documentation
|
215
232
|
- Suggest or add new features
|
216
233
|
|
data/Rakefile
CHANGED
@@ -20,12 +20,6 @@
|
|
20
20
|
.col-sm-10.controls
|
21
21
|
= file_field_tag :file, :class => "form-control"
|
22
22
|
%p.help-block= t('admin.import.help.file_limit', limit: RailsAdminImport.config.line_item_limit)
|
23
|
-
.form-group.control-group
|
24
|
-
%label.col-sm-2.control-label{for: "import_format"}= t("admin.import.format")
|
25
|
-
.col-sm-10.controls
|
26
|
-
= select_tag 'import_format',
|
27
|
-
options_for_select(RailsAdminImport::Formats.all),
|
28
|
-
data: { enumeration: true }
|
29
23
|
.form-group.control-group
|
30
24
|
%label.col-sm-2.control-label{for: "encoding"}= t("admin.import.encoding")
|
31
25
|
.col-sm-10.controls
|
@@ -42,7 +36,7 @@
|
|
42
36
|
%label.col-sm-2.control-label{for: "update_lookup"}= t("admin.import.update_lookup")
|
43
37
|
.col-sm-10.controls
|
44
38
|
= select_tag 'update_lookup',
|
45
|
-
options_for_select(@import_model.
|
39
|
+
options_for_select(@import_model.update_lookup_field_names,
|
46
40
|
@import_model.config.mapping_key.to_s), data: { enumeration: true }
|
47
41
|
|
48
42
|
- unless @import_model.association_fields.empty?
|
@@ -19,8 +19,9 @@ module RailsAdmin
|
|
19
19
|
@import_model = RailsAdminImport::ImportModel.new(@abstract_model)
|
20
20
|
|
21
21
|
if request.post?
|
22
|
+
format = RailsAdminImport::Formats.from_file(params[:file])
|
22
23
|
record_importer = RailsAdminImport::Formats.for(
|
23
|
-
|
24
|
+
format, @import_model, params)
|
24
25
|
|
25
26
|
if record_importer.valid?
|
26
27
|
importer = RailsAdminImport::Importer.new(
|
@@ -9,6 +9,11 @@ module RailsAdminImport
|
|
9
9
|
attr_accessor :header_converter
|
10
10
|
attr_accessor :csv_options
|
11
11
|
|
12
|
+
# Default is to downcase headers and add underscores to convert into attribute names
|
13
|
+
HEADER_CONVERTER = lambda do |header|
|
14
|
+
header.parameterize.underscore
|
15
|
+
end
|
16
|
+
|
12
17
|
def model(model_name, &block)
|
13
18
|
unless @deprecation_shown
|
14
19
|
warn "RailsAdminImport::Config#model is deprecated. " \
|
@@ -26,7 +31,7 @@ module RailsAdminImport
|
|
26
31
|
@logging = false
|
27
32
|
@line_item_limit = 1000
|
28
33
|
@rollback_on_error = false
|
29
|
-
@header_converter =
|
34
|
+
@header_converter = HEADER_CONVERTER
|
30
35
|
@csv_options = {}
|
31
36
|
end
|
32
37
|
end
|
@@ -5,6 +5,11 @@ module RailsAdminImport
|
|
5
5
|
@registry[format.to_s] = klass
|
6
6
|
end
|
7
7
|
|
8
|
+
def from_file(file)
|
9
|
+
return unless file
|
10
|
+
File.extname(file.original_filename).sub(/^\./, '')
|
11
|
+
end
|
12
|
+
|
8
13
|
def for(format, *args)
|
9
14
|
@registry.fetch(format.to_s, DummyImporter).new(*args)
|
10
15
|
end
|
@@ -26,3 +31,4 @@ require "rails_admin_import/formats/dummy_importer"
|
|
26
31
|
require "rails_admin_import/formats/file_importer"
|
27
32
|
require "rails_admin_import/formats/csv_importer"
|
28
33
|
require "rails_admin_import/formats/json_importer"
|
34
|
+
require "rails_admin_import/formats/xlsx_importer"
|
@@ -1,20 +1,16 @@
|
|
1
1
|
require "csv"
|
2
|
-
require "rchardet"
|
3
2
|
|
4
3
|
module RailsAdminImport
|
5
4
|
module Formats
|
6
5
|
class CSVImporter < FileImporter
|
7
6
|
Formats.register(:csv, self)
|
8
7
|
|
9
|
-
|
10
|
-
HEADER_CONVERTER = lambda do |header|
|
11
|
-
header.parameterize.underscore
|
12
|
-
end
|
8
|
+
autoload :CharDet, "rchardet"
|
13
9
|
|
14
10
|
def initialize(import_model, params)
|
15
11
|
super
|
16
12
|
@encoding = params[:encoding]
|
17
|
-
@header_converter = RailsAdminImport.config.header_converter
|
13
|
+
@header_converter = RailsAdminImport.config.header_converter
|
18
14
|
end
|
19
15
|
|
20
16
|
# A method that yields a hash of attributes for each record to import
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require "csv"
|
2
|
+
|
3
|
+
module RailsAdminImport
|
4
|
+
module Formats
|
5
|
+
class XLSXImporter < FileImporter
|
6
|
+
Formats.register(:xlsx, self)
|
7
|
+
|
8
|
+
autoload :SimpleXlsxReader, "simple_xlsx_reader"
|
9
|
+
|
10
|
+
def initialize(import_model, params)
|
11
|
+
super
|
12
|
+
@header_converter = RailsAdminImport.config.header_converter
|
13
|
+
end
|
14
|
+
|
15
|
+
# A method that yields a hash of attributes for each record to import
|
16
|
+
def each_record
|
17
|
+
doc = SimpleXlsxReader.open(filename)
|
18
|
+
sheet = doc.sheets.first
|
19
|
+
@headers = convert_headers(sheet.headers)
|
20
|
+
sheet.data.each do |row|
|
21
|
+
yield convert_to_attributes(row)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def convert_headers(headers)
|
28
|
+
headers.map do |h|
|
29
|
+
@header_converter.call(h || "")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def convert_to_attributes(row)
|
34
|
+
row_with_headers = @headers.zip(row)
|
35
|
+
row_with_headers.each_with_object({}) do |(field, value), record|
|
36
|
+
break if field.nil?
|
37
|
+
field = field.to_sym
|
38
|
+
if import_model.has_multiple_values?(field)
|
39
|
+
field = import_model.pluralize_field(field)
|
40
|
+
(record[field] ||= []) << value
|
41
|
+
else
|
42
|
+
record[field] = value
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -44,18 +44,28 @@ module RailsAdminImport
|
|
44
44
|
}
|
45
45
|
end
|
46
46
|
|
47
|
-
def
|
48
|
-
@
|
47
|
+
def single_association_fields
|
48
|
+
@single_association_fields ||= association_fields.select { |f|
|
49
49
|
!f.multiple?
|
50
50
|
}
|
51
51
|
end
|
52
52
|
|
53
|
-
def
|
54
|
-
@
|
55
|
-
|
53
|
+
def belongs_to_fields
|
54
|
+
@belongs_to_fields ||= single_association_fields.select { |f|
|
55
|
+
f.type == :belongs_to_association
|
56
56
|
}
|
57
57
|
end
|
58
58
|
|
59
|
+
def many_association_fields
|
60
|
+
@many_association_fields ||= association_fields.select { |f|
|
61
|
+
f.multiple?
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
def update_lookup_field_names
|
66
|
+
@update_lookup_field_names ||= model_fields.map(&:name) + belongs_to_fields.map(&:foreign_key)
|
67
|
+
end
|
68
|
+
|
59
69
|
def associated_object(field, mapping_field, value)
|
60
70
|
klass = association_class(field)
|
61
71
|
klass.where(mapping_field => value).first or
|
@@ -79,11 +89,11 @@ module RailsAdminImport
|
|
79
89
|
|
80
90
|
def has_multiple_values?(field_name)
|
81
91
|
plural_name = pluralize_field(field_name)
|
82
|
-
|
92
|
+
many_association_fields.any? { |field| field.name == field_name || field.name == plural_name }
|
83
93
|
end
|
84
94
|
|
85
95
|
def pluralize_field(field_name)
|
86
|
-
@plural_fields ||=
|
96
|
+
@plural_fields ||= many_association_fields.map(&:name).each_with_object({}) { |name, h|
|
87
97
|
h[name.to_s.singularize.to_sym] = name
|
88
98
|
}
|
89
99
|
@plural_fields[field_name] || field_name
|
@@ -70,8 +70,8 @@ module RailsAdminImport
|
|
70
70
|
action = object.new_record? ? :create : :update
|
71
71
|
|
72
72
|
begin
|
73
|
-
|
74
|
-
|
73
|
+
import_single_association_data(object, record)
|
74
|
+
import_many_association_data(object, record)
|
75
75
|
rescue AssociationNotFound => e
|
76
76
|
error = I18n.t("admin.import.association_not_found", :error => e.to_s)
|
77
77
|
report_error(object, action, error)
|
@@ -185,8 +185,8 @@ module RailsAdminImport
|
|
185
185
|
object
|
186
186
|
end
|
187
187
|
|
188
|
-
def
|
189
|
-
import_model.
|
188
|
+
def import_single_association_data(object, record)
|
189
|
+
import_model.single_association_fields.each do |field|
|
190
190
|
mapping_key = params[:associations][field.name]
|
191
191
|
value = extract_mapping(record[field.name], mapping_key)
|
192
192
|
|
@@ -196,8 +196,8 @@ module RailsAdminImport
|
|
196
196
|
end
|
197
197
|
end
|
198
198
|
|
199
|
-
def
|
200
|
-
import_model.
|
199
|
+
def import_many_association_data(object, record)
|
200
|
+
import_model.many_association_fields.each do |field|
|
201
201
|
if record.has_key? field.name
|
202
202
|
mapping_key = params[:associations][field.name]
|
203
203
|
values = record[field.name].reject { |value| value.blank? }.map { |value|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_admin_import
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Steph Skardal
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-08-
|
12
|
+
date: 2015-08-27 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -67,6 +67,34 @@ dependencies:
|
|
67
67
|
- - "~>"
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: '1.6'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: simple_xlsx_reader
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - "~>"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '1.0'
|
77
|
+
type: :runtime
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - "~>"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '1.0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: rubygems-tasks
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
70
98
|
description:
|
71
99
|
email:
|
72
100
|
- steph@endpoint.com
|
@@ -88,12 +116,14 @@ files:
|
|
88
116
|
- lib/rails_admin_import/config.rb
|
89
117
|
- lib/rails_admin_import/config/legacy_model.rb
|
90
118
|
- lib/rails_admin_import/config/sections/import.rb
|
119
|
+
- lib/rails_admin_import/eager_load.rb
|
91
120
|
- lib/rails_admin_import/engine.rb
|
92
121
|
- lib/rails_admin_import/formats.rb
|
93
122
|
- lib/rails_admin_import/formats/csv_importer.rb
|
94
123
|
- lib/rails_admin_import/formats/dummy_importer.rb
|
95
124
|
- lib/rails_admin_import/formats/file_importer.rb
|
96
125
|
- lib/rails_admin_import/formats/json_importer.rb
|
126
|
+
- lib/rails_admin_import/formats/xlsx_importer.rb
|
97
127
|
- lib/rails_admin_import/import_logger.rb
|
98
128
|
- lib/rails_admin_import/import_model.rb
|
99
129
|
- lib/rails_admin_import/importer.rb
|
@@ -124,4 +154,3 @@ signing_key:
|
|
124
154
|
specification_version: 4
|
125
155
|
summary: Import functionality for Rails Admin
|
126
156
|
test_files: []
|
127
|
-
has_rdoc:
|