col_active_importer_starter 0.1.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 +7 -0
- data/README.md +149 -0
- data/Rakefile +8 -0
- data/app/assets/config/col_active_importer_starter_manifest.js +1 -0
- data/app/assets/stylesheets/col_active_importer_starter/application.css +15 -0
- data/app/controllers/col_active_importer_starter/application_controller.rb +4 -0
- data/app/helpers/col_active_importer_starter/application_helper.rb +4 -0
- data/app/jobs/col_active_importer_starter/application_job.rb +4 -0
- data/app/mailers/col_active_importer_starter/application_mailer.rb +6 -0
- data/app/models/col_active_importer_starter/application_record.rb +5 -0
- data/app/views/layouts/col_active_importer_starter/application.html.erb +15 -0
- data/config/routes.rb +2 -0
- data/lib/col_active_importer_starter/engine.rb +5 -0
- data/lib/col_active_importer_starter/lib.rb +141 -0
- data/lib/col_active_importer_starter/version.rb +3 -0
- data/lib/col_active_importer_starter.rb +11 -0
- data/lib/tasks/col_active_importer_starter_tasks.rake +4 -0
- metadata +105 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8640f42dbcfff94ba0d58115a6a78ec859fe2dc63e9d695e36dab8546871e9d4
|
4
|
+
data.tar.gz: 723b1c2c15c2b53d07e1891edc493c1f1156d541a0155db0ff550d98a60e3790
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7854b72e834966f362ca3acad0cf5a94ecc725b022d377e89b6842674b2aef46b40ed5156941cab9853eba776a76f07cf8a0200cb0ab21b82037e721b76b527c
|
7
|
+
data.tar.gz: 5ed2ae585209d7baec0e3096fb9371e89ca18af9b521c738814078757a75b8085583f1a150ce990b4652e60a603b620d430c8a20169ed02692526cd895d2874d
|
data/README.md
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
# col_active_importer_starter
|
2
|
+
|
3
|
+
col_active_importer_starter is a starter(or wrapper) to [active_importer - https://github.com/continuum/active_importer](https://github.com/continuum/active_importer) gem.
|
4
|
+
|
5
|
+
## Features
|
6
|
+
|
7
|
+
`col_active_importer_starter` makes full use of `active_importer` gem to import tabular data from spreadsheets or similar sources into Active Record models.
|
8
|
+
|
9
|
+
- The best practices of `active_importer`, such as:
|
10
|
+
- [Events and callbacks - https://github.com/continuum/active_importer/wiki/Callbacks](https://github.com/continuum/active_importer/wiki/Callbacks).
|
11
|
+
- Introduce a optional cache to retain data in the memory
|
12
|
+
- Write out a file with the original data and more information for result
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Add this line to your application's Gemfile:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
gem 'col_active_importer_starter'
|
20
|
+
```
|
21
|
+
|
22
|
+
And then execute:
|
23
|
+
|
24
|
+
```shell
|
25
|
+
bundle
|
26
|
+
```
|
27
|
+
|
28
|
+
Or install it yourself as:
|
29
|
+
|
30
|
+
```shell
|
31
|
+
gem install col_active_importer_starter
|
32
|
+
```
|
33
|
+
|
34
|
+
## Usages
|
35
|
+
|
36
|
+
Suppose there is a ActiveRecord model `Article`:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
class Article < ApplicationRecord
|
40
|
+
|
41
|
+
end
|
42
|
+
```
|
43
|
+
and tabular data file `data/Articles.xlsx`
|
44
|
+
|
45
|
+
| Title | Body |
|
46
|
+
|-----------------|-----------------|
|
47
|
+
| Article.1.title | Article.1.body |
|
48
|
+
| Article.2.title | Article.2.body |
|
49
|
+
|
50
|
+
1. Create a `ArticleImporter` extend `ColActiveImporterStarter::BaseImporter`
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
# app/importers/article_import.rb
|
54
|
+
|
55
|
+
class ArticleImporter < ColActiveImporterStarter::BaseImporter
|
56
|
+
imports Article
|
57
|
+
|
58
|
+
transactional
|
59
|
+
module ColumnName
|
60
|
+
Title = "Title"
|
61
|
+
Body = "Body"
|
62
|
+
end
|
63
|
+
|
64
|
+
column ColumnName::Title, :title
|
65
|
+
column ColumnName::Body, :body
|
66
|
+
|
67
|
+
def handle_fetch_model
|
68
|
+
params = {
|
69
|
+
title: row[ColumnName::Title],
|
70
|
+
}
|
71
|
+
|
72
|
+
model = Article.find_or_initialize_by(params)
|
73
|
+
|
74
|
+
model
|
75
|
+
end
|
76
|
+
|
77
|
+
fetch_model do
|
78
|
+
handle_fetch_model
|
79
|
+
end
|
80
|
+
|
81
|
+
def handle_skip_rows_if?
|
82
|
+
row[ColumnName::Title].blank?
|
83
|
+
end
|
84
|
+
|
85
|
+
skip_rows_if do
|
86
|
+
handle_skip_rows_if?
|
87
|
+
end
|
88
|
+
|
89
|
+
# ArticleImporter.execute
|
90
|
+
def self.execute(file = "#{Rails.root}/data/Articles.1.xlsx")
|
91
|
+
params = {
|
92
|
+
cache: {},
|
93
|
+
file: file,
|
94
|
+
result_index: 10,
|
95
|
+
}
|
96
|
+
import(file, params: params)
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
end
|
101
|
+
```
|
102
|
+
|
103
|
+
2. Import data from a file.
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
ArticleImporter.execute("#{Rails.root}/data/Articles.1.xlsx")
|
107
|
+
```
|
108
|
+
|
109
|
+
Or specify more arguments.
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
params = {
|
113
|
+
cache: {},
|
114
|
+
file: "#{Rails.root}/data/Articles.1.xlsx",
|
115
|
+
result_index: 10,
|
116
|
+
}
|
117
|
+
|
118
|
+
ArticleImporter.import(file, params: params)
|
119
|
+
```
|
120
|
+
|
121
|
+
3. Then, check `tmp/importers` directory to find the result file.
|
122
|
+
|
123
|
+
| Title | Body | | Result ID | Result Message |
|
124
|
+
|-----------------|-----------------|---|-----------|-----------------|
|
125
|
+
| Article.1.title | Article.1.body | | 1 | success |
|
126
|
+
| Article.2.title | Article.2.body | | 2 | success |
|
127
|
+
|
128
|
+
## Inspire
|
129
|
+
|
130
|
+
Inspire by [active_importer - https://github.com/continuum/active_importer](https://github.com/continuum/active_importer).
|
131
|
+
|
132
|
+
## Contributing
|
133
|
+
|
134
|
+
Contributions are welcome! Take a look at our contributions guide for details.
|
135
|
+
The basic workflow for contributing is the following:
|
136
|
+
|
137
|
+
- [Fork it - https://github.com/CloudoLife/col_active_importer_starter/fork](https://github.com/CloudoLife/col_active_importer_starter/fork)
|
138
|
+
- Create your feature branch (git checkout -b my-new-feature)
|
139
|
+
- Commit your changes (git commit -am 'Add some feature')
|
140
|
+
- Push to the branch (git push origin my-new-feature)
|
141
|
+
- Create new Pull Request
|
142
|
+
|
143
|
+
## License
|
144
|
+
|
145
|
+
The gem is available as open source under the terms of the [MIT License - https://opensource.org/licenses/MIT](https://opensource.org/licenses/MIT).
|
146
|
+
|
147
|
+
## References
|
148
|
+
|
149
|
+
[1] [continuum/active_importer: Define importers that load tabular data from spreadsheets or CSV files into any ActiveRecord-like ORM. - https://github.com/continuum/active_importer](https://github.com/continuum/active_importer)
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
//= link_directory ../stylesheets/col_active_importer_starter .css
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
+
* It is generally better to create a new file per style scope.
|
12
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*/
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Col active importer starter</title>
|
5
|
+
<%= csrf_meta_tags %>
|
6
|
+
<%= csp_meta_tag %>
|
7
|
+
|
8
|
+
<%= stylesheet_link_tag "col_active_importer_starter/application", media: "all" %>
|
9
|
+
</head>
|
10
|
+
<body>
|
11
|
+
|
12
|
+
<%= yield %>
|
13
|
+
|
14
|
+
</body>
|
15
|
+
</html>
|
data/config/routes.rb
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
|
2
|
+
# continuum/active_importer: Define importers that load tabular data from spreadsheets or CSV files into any ActiveRecord-like ORM.
|
3
|
+
# https://github.com/continuum/active_importer
|
4
|
+
module ColActiveImporterStarter
|
5
|
+
module ColumnName
|
6
|
+
Code = "Code"
|
7
|
+
|
8
|
+
Name = "Name"
|
9
|
+
Seq = 'Seq'
|
10
|
+
|
11
|
+
ParentCode = "Parent Code"
|
12
|
+
end
|
13
|
+
|
14
|
+
module ResultIndex
|
15
|
+
ID = :result_index
|
16
|
+
end
|
17
|
+
|
18
|
+
module ResultColumnName
|
19
|
+
ID = 'Result ID'
|
20
|
+
Message = 'Result Message'
|
21
|
+
Error = 'Result Error'
|
22
|
+
end
|
23
|
+
|
24
|
+
module ResultValue
|
25
|
+
Success = 'success'
|
26
|
+
Fail = 'fail'
|
27
|
+
Skip = 'skip'
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.handle_model_cache!(cache, key)
|
31
|
+
model = cache[key]
|
32
|
+
return model if model.present?
|
33
|
+
|
34
|
+
Rails.logger.info("Cache not found: #{key}")
|
35
|
+
model = yield(key) if block_given?
|
36
|
+
|
37
|
+
cache[key] = model
|
38
|
+
|
39
|
+
model
|
40
|
+
end
|
41
|
+
|
42
|
+
class BaseImporter < ActiveImporter::Base
|
43
|
+
|
44
|
+
def get_result_id_column_index
|
45
|
+
params[ResultIndex::ID]
|
46
|
+
end
|
47
|
+
|
48
|
+
def initialize_result_exporter
|
49
|
+
exporter = RubyXL::Parser.parse(params[:file])
|
50
|
+
exporter_sheet1 = exporter[0]
|
51
|
+
|
52
|
+
header_index = @header_index - 1
|
53
|
+
column_index = get_result_id_column_index
|
54
|
+
exporter_sheet1.add_cell(header_index, (column_index += 1), ResultColumnName::ID)
|
55
|
+
exporter_sheet1.add_cell(header_index, (column_index += 1), ResultColumnName::Message)
|
56
|
+
|
57
|
+
@exporter = exporter
|
58
|
+
@exporter_sheet1 = exporter_sheet1
|
59
|
+
end
|
60
|
+
|
61
|
+
def initialize_model_cache
|
62
|
+
model_cache = params.try(:[], :model_cache) || {}
|
63
|
+
|
64
|
+
@model_cache = model_cache
|
65
|
+
end
|
66
|
+
|
67
|
+
on :import_started do
|
68
|
+
initialize_result_exporter
|
69
|
+
initialize_model_cache
|
70
|
+
end
|
71
|
+
|
72
|
+
# on :row_skipped do
|
73
|
+
# sheet1 = @sheet1
|
74
|
+
#
|
75
|
+
# row_index = @row_index - @header_index
|
76
|
+
# column_index = ColumnIndex::Imported
|
77
|
+
# column_index += 1
|
78
|
+
# sheet1[row_index, (column_index += 1)] = ResultColumnName::Skip
|
79
|
+
# end
|
80
|
+
|
81
|
+
def handle_row_success
|
82
|
+
exporter_sheet1 = @exporter_sheet1
|
83
|
+
|
84
|
+
row_index = @row_index - @header_index
|
85
|
+
column_index = get_result_id_column_index
|
86
|
+
column_index += 1
|
87
|
+
exporter_sheet1.add_cell(row_index, (column_index += 1), ResultValue::Success)
|
88
|
+
end
|
89
|
+
|
90
|
+
on :row_success do
|
91
|
+
handle_row_success
|
92
|
+
end
|
93
|
+
|
94
|
+
def handle_row_error(e)
|
95
|
+
exporter_sheet1 = @exporter_sheet1
|
96
|
+
|
97
|
+
row_index = @row_index - @header_index
|
98
|
+
column_index = get_result_id_column_index
|
99
|
+
column_index += 1
|
100
|
+
exporter_sheet1.add_cell(row_index, (column_index += 1), ResultValue::Fail)
|
101
|
+
exporter_sheet1.add_cell(row_index, (column_index += 1), e.message)
|
102
|
+
end
|
103
|
+
|
104
|
+
on :row_error do |e|
|
105
|
+
handle_row_error(e)
|
106
|
+
end
|
107
|
+
|
108
|
+
def handle_row_processed
|
109
|
+
exporter_sheet1 = @exporter_sheet1
|
110
|
+
|
111
|
+
row_index = @row_index - @header_index
|
112
|
+
column_index = get_result_id_column_index
|
113
|
+
exporter_sheet1.add_cell(row_index, (column_index += 1), model&.id)
|
114
|
+
end
|
115
|
+
|
116
|
+
on :row_processed do
|
117
|
+
handle_row_processed
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
def handle_import_finished
|
122
|
+
exporter = @exporter
|
123
|
+
|
124
|
+
file = params[:file]
|
125
|
+
|
126
|
+
extname = '.xlsx'
|
127
|
+
if file.present?
|
128
|
+
extname = File.extname(file)
|
129
|
+
basename = File.basename(file, extname)
|
130
|
+
end
|
131
|
+
|
132
|
+
result_file = "tmp/Result-#{Time.now.strftime('%Y%m%d%H%M%S')}-#{basename}#{extname}"
|
133
|
+
|
134
|
+
exporter.write result_file
|
135
|
+
end
|
136
|
+
|
137
|
+
on :import_finished do
|
138
|
+
handle_import_finished
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: col_active_importer_starter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Benjamin CloudoLife
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-01-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: active_importer
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.2.6
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.2.6
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rubyXL
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: col_active_importer_starter makes full use of active_importer gem to
|
56
|
+
import tabular data from spreadsheets or similar sources into Active Record models.
|
57
|
+
email:
|
58
|
+
- benjamin@cloudolife.com
|
59
|
+
executables: []
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- README.md
|
64
|
+
- Rakefile
|
65
|
+
- app/assets/config/col_active_importer_starter_manifest.js
|
66
|
+
- app/assets/stylesheets/col_active_importer_starter/application.css
|
67
|
+
- app/controllers/col_active_importer_starter/application_controller.rb
|
68
|
+
- app/helpers/col_active_importer_starter/application_helper.rb
|
69
|
+
- app/jobs/col_active_importer_starter/application_job.rb
|
70
|
+
- app/mailers/col_active_importer_starter/application_mailer.rb
|
71
|
+
- app/models/col_active_importer_starter/application_record.rb
|
72
|
+
- app/views/layouts/col_active_importer_starter/application.html.erb
|
73
|
+
- config/routes.rb
|
74
|
+
- lib/col_active_importer_starter.rb
|
75
|
+
- lib/col_active_importer_starter/engine.rb
|
76
|
+
- lib/col_active_importer_starter/lib.rb
|
77
|
+
- lib/col_active_importer_starter/version.rb
|
78
|
+
- lib/tasks/col_active_importer_starter_tasks.rake
|
79
|
+
homepage: https://github.com/CloudoLife-RoR/col_active_importer_starter
|
80
|
+
licenses: []
|
81
|
+
metadata:
|
82
|
+
allowed_push_host: https://rubygems.org
|
83
|
+
homepage_uri: https://github.com/CloudoLife-RoR/col_active_importer_starter
|
84
|
+
source_code_uri: https://github.com/CloudoLife-RoR/col_active_importer_starter
|
85
|
+
changelog_uri: https://github.com/CloudoLife-RoR/col_active_importer_starter
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options: []
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
requirements: []
|
101
|
+
rubygems_version: 3.4.3
|
102
|
+
signing_key:
|
103
|
+
specification_version: 4
|
104
|
+
summary: col_active_importer_starter is a starter(or wrapper) to [active_importer.
|
105
|
+
test_files: []
|