active_admin_import 1.0.1 → 2.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.
- data/README.md +11 -5
- data/active_admin_import.gemspec +1 -2
- data/app/views/admin/import.html.erb +11 -7
- data/lib/active_admin_import.rb +10 -1
- data/lib/active_admin_import/dsl.rb +66 -22
- data/lib/active_admin_import/importer.rb +22 -15
- data/lib/active_admin_import/locales/en.yml +15 -0
- data/lib/active_admin_import/locales/it.yml +15 -0
- data/lib/active_admin_import/model.rb +27 -0
- data/lib/active_admin_import/version.rb +1 -1
- metadata +8 -16
data/README.md
CHANGED
@@ -14,14 +14,20 @@ https://github.com/zdennis/activerecord-import
|
|
14
14
|
|
15
15
|
# +back+:: resource action to redirect after processing
|
16
16
|
# +col_sep+:: column separator used for CSV parsing
|
17
|
-
# +validate+::
|
17
|
+
# +validate+:: true|false, means perfoem validations or not
|
18
18
|
# +batch_size+:: integer value of max record count inserted by 1 query/transaction
|
19
|
-
# +before_import+:: proc for before import action, called with
|
20
|
-
# +
|
21
|
-
# +
|
19
|
+
# +before_import+:: proc for before import action, hook called with importer object
|
20
|
+
# +after_import+:: proc for after import action, hook called with importer object
|
21
|
+
# +before_batch_import+:: proc for before each batch action, called with importer object
|
22
|
+
# +after_batch_import+:: proc for after each batch action, called with importer object
|
22
23
|
# +on_duplicate_key_update+:: an Array or Hash, tells activerecord-import to use MySQL's ON DUPLICATE KEY UPDATE ability.
|
23
24
|
# +timestamps+:: true|false, tells activerecord-import to not add timestamps (if false) even if record timestamps is disabled in ActiveRecord::Base
|
24
25
|
# +ignore+:: true|false, tells activerecord-import toto use MySQL's INSERT IGNORE ability
|
26
|
+
# +params_keys+:: params values available in callbacks
|
27
|
+
# +template+:: custom template rendering
|
28
|
+
# +locals+:: local variables for template
|
29
|
+
# +resource_class+:: resource class name
|
30
|
+
# +resource_label+:: resource label value
|
25
31
|
|
26
32
|
|
27
33
|
#Example
|
@@ -30,7 +36,7 @@ https://github.com/zdennis/activerecord-import
|
|
30
36
|
active_admin_import :validate => false,
|
31
37
|
:col_sep => ',',
|
32
38
|
:back => :index ,
|
33
|
-
:before_import => proc{|
|
39
|
+
:before_import => proc{|importer| resource.delete_all},
|
34
40
|
:batch_size => 1000
|
35
41
|
|
36
42
|
|
data/active_admin_import.gemspec
CHANGED
@@ -4,7 +4,7 @@ require File.expand_path('../lib/active_admin_import/version', __FILE__)
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.authors = ["Igor Fedoronchuk"]
|
6
6
|
gem.email = ["fedoronchuk@gmail.com"]
|
7
|
-
gem.description = "
|
7
|
+
gem.description = "The most efficient way to import for Active Admin"
|
8
8
|
gem.summary = "ActiveAdmin import based on activerecord-import gem."
|
9
9
|
gem.homepage = "http://github.com/Fivell/active_admin_import"
|
10
10
|
|
@@ -15,6 +15,5 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.require_paths = ["lib"]
|
16
16
|
gem.version = ActiveAdminImport::VERSION
|
17
17
|
|
18
|
-
gem.add_runtime_dependency('chronic')
|
19
18
|
gem.add_runtime_dependency('activerecord-import','0.3.0')
|
20
19
|
end
|
@@ -1,7 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
1
|
+
<p>
|
2
|
+
<small> <%= raw(@active_admin_import_model.hint) %> </small>
|
3
|
+
</p>
|
4
|
+
<%= semantic_form_for @active_admin_import_model , :url => {:action => :do_import}, :html => {:multipart => true} do |f| %>
|
5
|
+
<%= f.inputs do %>
|
6
|
+
<%= f.input :file, :as=>:file %>
|
7
|
+
<% end %>
|
8
|
+
<%= f.actions do %>
|
9
|
+
<%= f.action :submit , :label =>t("active_admin_import.import_btn") ,:button_html => { :disable_with => t("active_admin_import.import_btn_disabled") }%>
|
10
|
+
<% end %>
|
11
|
+
<% end %>
|
data/lib/active_admin_import.rb
CHANGED
@@ -3,5 +3,14 @@ require 'active_admin_import/version'
|
|
3
3
|
require 'active_admin_import/engine'
|
4
4
|
require 'active_admin_import/dsl'
|
5
5
|
require 'active_admin_import/importer'
|
6
|
-
|
6
|
+
require 'active_admin_import/model'
|
7
7
|
::ActiveAdmin::DSL.send(:include, ActiveAdminImport::DSL)
|
8
|
+
|
9
|
+
module ActiveAdminImport
|
10
|
+
class Railtie < ::Rails::Railtie
|
11
|
+
config.after_initialize do
|
12
|
+
require 'active_support/i18n'
|
13
|
+
I18n.load_path.unshift *Dir[File.expand_path('../active_admin_import/locales/*.yml', __FILE__)]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -7,45 +7,89 @@ module ActiveAdminImport
|
|
7
7
|
# Options
|
8
8
|
# +back+:: resource action to redirect after processing
|
9
9
|
# +col_sep+:: column separator used for CSV parsing
|
10
|
-
# +validate+::
|
10
|
+
# +validate+:: true|false, means perfoem validations or not
|
11
11
|
# +batch_size+:: integer value of max record count inserted by 1 query/transaction
|
12
|
-
# +before_import+:: proc for before import action, called with
|
13
|
-
# +
|
14
|
-
# +
|
12
|
+
# +before_import+:: proc for before import action, hook called with importer object
|
13
|
+
# +after_import+:: proc for after import action, hook called with importer object
|
14
|
+
# +before_batch_import+:: proc for before each batch action, called with importer object
|
15
|
+
# +after_batch_import+:: proc for after each batch action, called with importer object
|
15
16
|
# +on_duplicate_key_update+:: an Array or Hash, tells activerecord-import to use MySQL's ON DUPLICATE KEY UPDATE ability.
|
16
17
|
# +timestamps+:: true|false, tells activerecord-import to not add timestamps (if false) even if record timestamps is disabled in ActiveRecord::Base
|
17
18
|
# +ignore+:: true|false, tells activerecord-import toto use MySQL's INSERT IGNORE ability
|
19
|
+
# +fetch_extra_options_from_params+:: params values available in callbacks in importer.extra_options hash
|
20
|
+
# +template+:: custom template rendering
|
21
|
+
# +locals+:: local variables for template
|
22
|
+
# +resource_class+:: resource class name
|
23
|
+
# +resource_label+:: resource label value
|
24
|
+
#
|
18
25
|
def active_admin_import options = {}
|
19
26
|
default_options = {
|
20
|
-
|
21
|
-
|
27
|
+
:back => :import,
|
28
|
+
:col_sep => ',',
|
29
|
+
:template => "admin/import",
|
30
|
+
:template_object => ActiveAdminImport::Model.new,
|
31
|
+
:fetch_extra_options_from_params => [],
|
32
|
+
:resource_class => nil,
|
33
|
+
:resource_label => nil,
|
34
|
+
:headers_rewrites => {}
|
35
|
+
|
36
|
+
|
22
37
|
}
|
23
38
|
options = default_options.merge(options)
|
24
|
-
|
25
|
-
|
26
|
-
end
|
39
|
+
params_key = ActiveModel::Naming.param_key(options[:template_object])
|
40
|
+
|
27
41
|
|
28
42
|
collection_action :import, :method => :get do
|
29
|
-
|
43
|
+
@active_admin_import_model = options[:template_object]
|
44
|
+
render :template => options[:template]
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
action_item :only => :index do
|
49
|
+
link_to(I18n.t('active_admin_import.import_model',
|
50
|
+
:model => (options[:resource_label] || active_admin_config.resource_name)),
|
51
|
+
:action => 'import')
|
30
52
|
end
|
31
53
|
|
54
|
+
|
32
55
|
collection_action :do_import, :method => :post do
|
33
|
-
if params[
|
34
|
-
flash[:alert] =
|
35
|
-
return redirect_to :
|
56
|
+
if params[params_key].blank?
|
57
|
+
flash[:alert] = I18n.t('active_admin_import.no_file_error')
|
58
|
+
return redirect_to :back
|
36
59
|
end
|
37
|
-
|
38
|
-
|
39
|
-
|
60
|
+
content_types_allow = [
|
61
|
+
'text/csv',
|
62
|
+
'text/x-csv',
|
63
|
+
'text/comma-separated-values',
|
64
|
+
'application/csv',
|
65
|
+
'application/vnd.ms-excel',
|
66
|
+
'application/vnd.msexcel'
|
67
|
+
]
|
68
|
+
unless params[params_key]['file'].try(:content_type) && params[params_key]['file'].content_type.in?(content_types_allow)
|
69
|
+
flash[:alert] = I18n.t('active_admin_import.file_format_error')
|
70
|
+
return redirect_to :back
|
40
71
|
end
|
41
|
-
importer = Importer.new( active_admin_config.resource_class, params[:import][:file], options)
|
42
72
|
|
73
|
+
importer = Importer.new((options[:resource_class] || active_admin_config.resource_class),
|
74
|
+
params[params_key][:file],
|
75
|
+
options,
|
76
|
+
params[params_key].to_hash.slice(*options[:fetch_extra_options_from_params])
|
77
|
+
)
|
78
|
+
result = importer.import
|
79
|
+
|
80
|
+
flash[:notice] = I18n.t('active_admin_import.imported',
|
81
|
+
:count=> result[:imported].to_i,
|
82
|
+
:model => (options[:resource_label] || active_admin_config.resource_label).downcase,
|
83
|
+
:plural_model => (options[:resource_label].present? ? options[:resource_label].to_s.pluralize : active_admin_config.plural_resource_label).downcase
|
84
|
+
|
85
|
+
) if result[:imported].to_i > 0
|
86
|
+
|
87
|
+
flash[:error] = I18n.t('active_admin_import.failed',
|
88
|
+
:count=> result[:failed].count,
|
89
|
+
:model => (options[:resource_label] || active_admin_config.resource_label).downcase,
|
90
|
+
:plural_model => (options[:resource_label].present? ? options[:resource_label].to_s.pluralize : active_admin_config.plural_resource_label).downcase
|
43
91
|
|
44
|
-
|
45
|
-
flash[:notice] = "#{view_context.pluralize(result[:imported].to_i,active_admin_config.resource_name)} was imported"
|
46
|
-
unless result[:failed].count == 0
|
47
|
-
flash[:error] = "#{view_context.pluralize(result[:failed].count,active_admin_config.resource_name)} was failed to imported"
|
48
|
-
end
|
92
|
+
) if result[:failed].count > 0
|
49
93
|
|
50
94
|
redirect_to :action => options[:back]
|
51
95
|
end
|
@@ -2,28 +2,33 @@ require 'csv'
|
|
2
2
|
module ActiveAdminImport
|
3
3
|
class Importer
|
4
4
|
|
5
|
-
attr_reader :resource, :file, :options , :result
|
5
|
+
attr_reader :resource, :file, :options , :extra_options , :result ,
|
6
|
+
:cycle_data, :headers , :csv_lines
|
6
7
|
|
7
|
-
def store
|
8
|
+
def store
|
8
9
|
result = @resource.transaction do
|
9
|
-
options[:before_batch_import].call(
|
10
|
-
|
10
|
+
options[:before_batch_import].call(self) if options[:before_batch_import].is_a?(Proc)
|
11
|
+
|
12
|
+
|
13
|
+
result = resource.import headers.values, csv_lines, {
|
11
14
|
:validate => options[:validate],
|
12
15
|
:on_duplicate_key_update => options[:on_duplicate_key_update],
|
13
16
|
:ignore => options[:ignore],
|
14
17
|
:timestamps => options[:timestamps]
|
15
18
|
}
|
16
|
-
options[:after_batch_import].call(
|
19
|
+
options[:after_batch_import].call(self) if options[:after_batch_import].is_a?(Proc)
|
17
20
|
result
|
18
21
|
end
|
19
|
-
{:imported =>
|
22
|
+
{:imported => csv_lines.count - result.failed_instances.count , :failed => result.failed_instances}
|
20
23
|
end
|
21
24
|
|
22
25
|
def prepare_headers(headers)
|
23
|
-
Hash[headers.zip(headers.map { |el| el.underscore.gsub(/\s+/, '_') })]
|
26
|
+
@headers = Hash[headers.zip(headers.map { |el| el.underscore.gsub(/\s+/, '_') })]
|
27
|
+
@headers.merge!(options[:headers_rewrites])
|
28
|
+
@headers
|
24
29
|
end
|
25
30
|
|
26
|
-
def initialize resource, file, options
|
31
|
+
def initialize resource, file, options , extra_options = nil
|
27
32
|
@resource = resource
|
28
33
|
@file = file
|
29
34
|
@options = {
|
@@ -36,20 +41,22 @@ module ActiveAdminImport
|
|
36
41
|
:failed => [],
|
37
42
|
:imported => 0
|
38
43
|
}
|
44
|
+
@extra_options = extra_options
|
45
|
+
@csv_options = @options.slice(:col_sep, :row_sep)
|
39
46
|
end
|
40
47
|
|
41
48
|
def cycle(lines)
|
42
|
-
|
43
|
-
@result.merge!(self.store
|
49
|
+
@csv_lines = CSV.parse(lines.join, @csv_options)
|
50
|
+
@result.merge!(self.store){|key,val1,val2| val1+val2}
|
44
51
|
end
|
45
52
|
|
46
53
|
def import
|
47
|
-
options[:before_import].call(
|
54
|
+
options[:before_import].call(self) if options[:before_import].is_a?(Proc)
|
48
55
|
lines = []
|
49
|
-
batch_size =
|
56
|
+
batch_size = options[:batch_size].to_i
|
50
57
|
IO.foreach(file.path) do |line|
|
51
|
-
if
|
52
|
-
|
58
|
+
if headers.empty?
|
59
|
+
prepare_headers(CSV.parse(line, @csv_options).first)
|
53
60
|
else
|
54
61
|
lines << line
|
55
62
|
if lines.size >= batch_size
|
@@ -59,7 +66,7 @@ module ActiveAdminImport
|
|
59
66
|
end
|
60
67
|
end
|
61
68
|
cycle(lines) unless lines.blank?
|
62
|
-
options[:after_import].call(
|
69
|
+
options[:after_import].call(self) if options[:after_import].is_a?(Proc)
|
63
70
|
result
|
64
71
|
end
|
65
72
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
en:
|
2
|
+
active_admin:
|
3
|
+
import: "Import"
|
4
|
+
active_admin_import:
|
5
|
+
file_format_error: "You can import only valid csv file"
|
6
|
+
no_file_error: "Please, select file to import"
|
7
|
+
imported:
|
8
|
+
one: "Successfully imported 1 %{model}"
|
9
|
+
other: "Successfully imported %{count} %{plural_model}"
|
10
|
+
failed:
|
11
|
+
one: "Failed to import 1 %{model}"
|
12
|
+
other: "Failed to import %{count} %{plural_model}"
|
13
|
+
import_model: "Import %{model}"
|
14
|
+
import_btn: "Import"
|
15
|
+
import_btn_disabled: "Wait..."
|
@@ -0,0 +1,15 @@
|
|
1
|
+
it:
|
2
|
+
active_admin:
|
3
|
+
import: "Importa"
|
4
|
+
active_admin_import:
|
5
|
+
file_format_error: "Puoi importare solo CSV conformi"
|
6
|
+
no_file_error: "Per favore, seleziona un file da importare"
|
7
|
+
imported:
|
8
|
+
one: "Importato 1 %{model} con successo"
|
9
|
+
other: "Importati %{count} %{plural_model} con successo"
|
10
|
+
failed:
|
11
|
+
one: "Importazione di 1 %{model} fallita"
|
12
|
+
other: "Importazione di %{count} %{plural_model} fallita"
|
13
|
+
import_model: "Importa %{model}"
|
14
|
+
import_btn: "Importa"
|
15
|
+
import_btn_disabled: "In attesa..."
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module ActiveAdminImport
|
2
|
+
class Model
|
3
|
+
extend ActiveModel::Naming
|
4
|
+
include ActiveModel::Conversion
|
5
|
+
|
6
|
+
attr_accessor :file
|
7
|
+
attr_accessor :hint
|
8
|
+
attr_reader :attributes
|
9
|
+
|
10
|
+
def initialize(attributes={})
|
11
|
+
self.hint= attributes.delete(:hint)
|
12
|
+
@attributes = attributes
|
13
|
+
@attributes.each do |key,value|
|
14
|
+
#generate methods for instance object by attributes
|
15
|
+
singleton_class.class_eval do
|
16
|
+
define_method(key) { self.attributes[key] } unless method_defined? key
|
17
|
+
define_method("#{key}=") { |new_value| @attributes[key] = new_value } unless method_defined? "#{key}="
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def persisted?
|
23
|
+
false
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_admin_import
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,22 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-05-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
-
- !ruby/object:Gem::Dependency
|
15
|
-
name: chronic
|
16
|
-
requirement: &70313477456520 !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
|
-
requirements:
|
19
|
-
- - ! '>='
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
version: '0'
|
22
|
-
type: :runtime
|
23
|
-
prerelease: false
|
24
|
-
version_requirements: *70313477456520
|
25
14
|
- !ruby/object:Gem::Dependency
|
26
15
|
name: activerecord-import
|
27
|
-
requirement: &
|
16
|
+
requirement: &70124414344240 !ruby/object:Gem::Requirement
|
28
17
|
none: false
|
29
18
|
requirements:
|
30
19
|
- - =
|
@@ -32,8 +21,8 @@ dependencies:
|
|
32
21
|
version: 0.3.0
|
33
22
|
type: :runtime
|
34
23
|
prerelease: false
|
35
|
-
version_requirements: *
|
36
|
-
description:
|
24
|
+
version_requirements: *70124414344240
|
25
|
+
description: The most efficient way to import for Active Admin
|
37
26
|
email:
|
38
27
|
- fedoronchuk@gmail.com
|
39
28
|
executables: []
|
@@ -51,6 +40,9 @@ files:
|
|
51
40
|
- lib/active_admin_import/dsl.rb
|
52
41
|
- lib/active_admin_import/engine.rb
|
53
42
|
- lib/active_admin_import/importer.rb
|
43
|
+
- lib/active_admin_import/locales/en.yml
|
44
|
+
- lib/active_admin_import/locales/it.yml
|
45
|
+
- lib/active_admin_import/model.rb
|
54
46
|
- lib/active_admin_import/version.rb
|
55
47
|
homepage: http://github.com/Fivell/active_admin_import
|
56
48
|
licenses: []
|