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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8a37478fcdb96c3cddb93ac6f85dc1fa43329f32
4
- data.tar.gz: 8b36ca27a1b441bebd19a6cb3a80865063975160
3
+ metadata.gz: d22596961dbc1568f035e4f5c6e5896fcfb01474
4
+ data.tar.gz: 407a068d2bf2d62e096ec46c4c061b559db98bec
5
5
  SHA512:
6
- metadata.gz: 037159e831272b29da9d07093f43fdb7e212ce92f4a28c02c7bc836b634239d4285e04f6fe102a6f402203644d4d81bc67388e7b75c1518674d63fb26eda6b49
7
- data.tar.gz: c323b72bfd8d3980e11e06eadf83b34c184fcf3fd04d8ed73880dc45741d518b0d37cd0dcc37f698df1d64055e634e94c67db4797e81a652af84f428f7bc754a
6
+ metadata.gz: d1d2338cbf97015e11c114b1ee6d68994c8517942497ce839f029ac02e36d133f8bd9866634e23e5e2825d9a88033c25e5508016a209f39d48d593edcf2c376f
7
+ data.tar.gz: 82fa136b73f126c8dcabaa7e83e472b0815b0231286d505be16718c15a7b8f9aa425fee723e67424419dd5e94a51182adbd6133238f4382b2d4f36df5ce96f80
@@ -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 JSON files
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.0. If you are still using version 0.1.x, see [this branch](https://github.com/stephskardal/rails_admin_import/tree/legacy)*
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.0.0"
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 `nil`): 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.
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/ankane/blazer/issues)
213
- - Fix bugs and [submit pull requests](https://github.com/ankane/blazer/pulls)
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
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env rake
2
2
 
3
- require 'bundler'
4
- Bundler::GemHelper.install_tasks
3
+ require 'rubygems/tasks'
4
+ Gem::Tasks.new
5
5
 
6
6
  # Piggyback off the Rails Admin rake tasks to set up the CI environment
7
7
  spec = Gem::Specification.find_by_name 'rails_admin'
@@ -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.model_fields.map(&:name),
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
- params[:import_format] || "csv", @import_model, params)
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 = nil
34
+ @header_converter = HEADER_CONVERTER
30
35
  @csv_options = {}
31
36
  end
32
37
  end
@@ -0,0 +1,3 @@
1
+ require "rails_admin_import"
2
+ require "rchardet"
3
+ require "simple_xlsx_reader"
@@ -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
- # Default is to downcase headers and add underscores to convert into attribute names
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 || 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 belongs_to_fields
48
- @belongs_to_fields ||= association_fields.select { |f|
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 many_fields
54
- @many_fields ||= association_fields.select {
55
- |f| f.multiple?
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
- many_fields.any? { |field| field.name == field_name || field.name == plural_name }
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 ||= many_fields.map(&:name).each_with_object({}) { |name, h|
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
- import_belongs_to_data(object, record)
74
- import_has_many_data(object, record)
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 import_belongs_to_data(object, record)
189
- import_model.belongs_to_fields.each do |field|
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 import_has_many_data(object, record)
200
- import_model.many_fields.each do |field|
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|
@@ -1,3 +1,3 @@
1
1
  module RailsAdminImport
2
- VERSION = "1.1.0"
2
+ VERSION = "1.2.0"
3
3
  end
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.1.0
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-04 00:00:00.000000000 Z
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: