active_admin_import 2.0.1 → 2.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ODA4MTJlNTI0ODA4ZWUxZDcwODU4NjRhOWI4NzNlNzliNTE2MzliNA==
5
+ data.tar.gz: !binary |-
6
+ ZjkzY2M0MWZiOTk4OGNhZDg4ODllYWJiNjQyYjgyYWNiMWRlNzUzZg==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ M2I5NTVkM2Y4NTI5MzgzNGMxNDU5MTYxYjc5NjY4MzU1Yzc5NTVkNjE3MDAx
10
+ MzQyMmFlMTgyNTRjMGJkNDYzZGFhZTM2MzJlOGRjZDcyNGQzYTFlMDgwMjYz
11
+ MjlhMjE2NGUwZDU1NjM4ZTNhZDM5ZGFkYTk3NzY3ZThiY2I0NWU=
12
+ data.tar.gz: !binary |-
13
+ MzQzZWNjYTkxYmM1NmE3NjBhNmUzOTIzM2Y2YjZkMWJkZWI1NDg1NTFiMjU4
14
+ ODM3NzRhNmE1M2FiM2I0OGFmMzM0OGZkNDhjNDE4MjJlNTlkZGY2ZmQzNGRm
15
+ MTI3ZjlkOTFiMDlmYmFjYjVhN2VjOGFkOGVmMjMwNDlhNDc0MDQ=
data/README.md CHANGED
@@ -1,25 +1,42 @@
1
- # ActiveAdminImport
1
+ # ActiveAdminImport
2
2
  The most fastest and efficient CSV import for Active Admin (based on activerecord-import gem)
3
3
  with support of validations and bulk inserts
4
4
 
5
5
 
6
- #Links
7
- https://github.com/gregbell/active_admin
6
+ Current master works with AA 0-6-stable branch
8
7
 
9
- https://github.com/zdennis/activerecord-import
8
+ #Why yet another import for ActiveAdmin ? Now with activerecord-import ....
9
+
10
+ "Because plain-vanilla, out-of-the-box ActiveRecord doesn’t provide support for inserting large amounts of data efficiently"
11
+
12
+ cool features of activerecord-import
13
+
14
+ activerecord-import can perform validations (fast)
15
+ activerecord-import can perform on duplicate key updates (requires mysql)
10
16
 
11
17
 
18
+ #So active_admin_import features
19
+
20
+ Encoding handling
21
+ Support importing with ZIP file
22
+ Two step importing (see example2)
23
+ CSV options
24
+ Ability to prepend CSV headers automatically
25
+ Bulk import (activerecord-import)
26
+ Ability to customize template
27
+ Callbacks support
28
+ and more ....
29
+
12
30
  #Options
13
31
 
14
32
  # +back+:: resource action to redirect after processing
15
- # +col_sep+:: column separator used for CSV parsing
33
+ # +csv_options+:: hash with column separator, row separator, etc
16
34
  # +validate+:: true|false, means perfoem validations or not
17
35
  # +batch_size+:: integer value of max record count inserted by 1 query/transaction
18
36
  # +before_import+:: proc for before import action, hook called with importer object
19
37
  # +after_import+:: proc for after import action, hook called with importer object
20
38
  # +before_batch_import+:: proc for before each batch action, called with importer object
21
39
  # +after_batch_import+:: proc for after each batch action, called with importer object
22
- # +fetch_extra_options_from_params+:: params available in callbacks ( importer.extra_options proprty hash )
23
40
  # +on_duplicate_key_update+:: an Array or Hash, tells activerecord-import to use MySQL's ON DUPLICATE KEY UPDATE ability.
24
41
  # +timestamps+:: true|false, tells activerecord-import to not add timestamps (if false) even if record timestamps is disabled in ActiveRecord::Base
25
42
  # +ignore+:: true|false, tells activerecord-import toto use MySQL's INSERT IGNORE ability
@@ -33,24 +50,23 @@ https://github.com/zdennis/activerecord-import
33
50
 
34
51
 
35
52
 
36
- Default options values
37
-
38
- :back => :import,
39
- :col_sep => ',',
40
- :template => "admin/import",
41
- :template_object => ActiveAdminImport::Model.new,
42
- :fetch_extra_options_from_params => [],
43
- :resource_class => nil,
44
- :resource_label => nil,
53
+ #Default options values
54
+
55
+ back: {action: :import},
56
+ csv_options: {},
57
+ template: "admin/import",
58
+ fetch_extra_options_from_params: [],
59
+ resource_class: config.resource_class,
60
+ resource_label: config.resource_label,
61
+ plural_resource_label: config.plural_resource_label,
45
62
 
46
63
 
47
- #Example
64
+ #Example1
48
65
 
49
66
  ActiveAdmin.register Post do
50
67
  active_admin_import :validate => false,
51
- :col_sep => ',',
52
- :back => :index ,
53
- :before_import => proc{|importer| resource.delete_all},
68
+ :csv_options => {:col_sep => ";" },
69
+ :before_import => proc{ Post.delete_all},
54
70
  :batch_size => 1000
55
71
 
56
72
 
@@ -58,6 +74,113 @@ Default options values
58
74
 
59
75
 
60
76
 
77
+ #Example2 Importing to mediate table with insert select operation after import completion
78
+
79
+ This config allows to replace data without downtime
80
+
81
+ ActiveAdmin.register Post do
82
+ active_admin_import :validate => false,
83
+ :csv_options => {:col_sep => ";" },
84
+ :resource_class => ImportedPost , # we import data into another resource
85
+ :before_import => proc{ ImportedPost.delete_all },
86
+ :after_import => proc{
87
+ Post.transaction do
88
+ Post.delete_all
89
+ Post.connection.execute("INSERT INTO posts (SELECT * FROM import_posts)")
90
+ end
91
+ },
92
+ :back => proc { config.namespace.resource_for(Post).route_collection_path } # redirect to post index
93
+ end
94
+
95
+
96
+
97
+ #Example3 Importing file without headers, but we always know file format, so we can predefine it
98
+
99
+ ActiveAdmin.register Post do
100
+ active_admin_import :validate => true,
101
+ :template_object => ActiveAdminImport::Model.new(
102
+ :hint => "file will be imported with such header format: 'body','title','author'",
103
+ :csv_headers => ["body","title","author"]
104
+ )
105
+ end
106
+
107
+
108
+ #Example4 Importing without forcing to UTF-8 and disallow archives
109
+
110
+ ActiveAdmin.register Post do
111
+ active_admin_import :validate => true,
112
+ :template_object => ActiveAdminImport::Model.new(
113
+ :hint => "file will be encoded to ISO-8859-1",
114
+ :force_encoding => "ISO-8859-1",
115
+ :allow_archive => false
116
+ )
117
+ end
118
+
119
+
120
+
121
+ #Example5 Callbacks for each bulk insert iteration
122
+
123
+ ActiveAdmin.register Post do
124
+ active_admin_import :validate => true,
125
+ :before_batch_import => proc { |import|
126
+ import.file #current file used
127
+ import.resource #ActiveRecord class to import to
128
+ import.options # options
129
+ import.result # result before bulk iteration
130
+ import.headers # CSV headers
131
+ import.csv_lines #lines to import
132
+ import.model #template_object instance
133
+ },
134
+ :before_batch_import => proc{ |import|
135
+
136
+ }
137
+ end
138
+
139
+
140
+ #Example6 dynamic CSV options, template overriding
141
+
142
+ 1) put overrided template to app/views/import.html.erb
143
+
144
+
145
+ <p>
146
+ <small> <%= raw(@active_admin_import_model.hint) %> </small>
147
+ </p>
148
+ <%= semantic_form_for @active_admin_import_model, url: {action: :do_import}, html: {multipart: true} do |f| %>
149
+ <%= f.inputs do %>
150
+ <%= f.input :file, as: :file %>
151
+ <% end %>
152
+ <%= f.inputs "CSV options", :for => [:csv_options, OpenStruct.new(@active_admin_import_model.csv_options)] do |csv| %>
153
+ <% csv.with_options :input_html => {:style => 'width:40px;'} do |opts| %>
154
+ <%= opts.input :col_sep %>
155
+ <%= opts.input :row_sep %>
156
+ <%= opts.input :quote_char %>
157
+ <% end %>
158
+ <% end %>
159
+
160
+ <%= f.actions do %>
161
+ <%= f.action :submit, label: t("active_admin_import.import_btn"), button_html: {disable_with: t("active_admin_import.import_btn_disabled")} %>
162
+ <% end %>
163
+ <% end %>
164
+
165
+
166
+
167
+ 2) call method with following parameters
168
+
169
+ ActiveAdmin.register Post do
170
+ active_admin_import :validate => false,
171
+ :template => 'import' ,
172
+ :template_object => ActiveAdminImport::Model.new(
173
+ :hint => "specify CSV options"
174
+ :csv_options => {:col_sep => ";", :row_sep => nil, :quote_char => nil}
175
+ )
176
+ end
177
+
178
+
179
+ #Links
180
+ https://github.com/gregbell/active_admin
181
+
182
+ https://github.com/zdennis/activerecord-import
183
+
61
184
  #Source Doc
62
- http://rubydoc.info/gems/active_admin_import/2.0.0/
185
+ http://rubydoc.info/gems/active_admin_import/2.1.0/
63
186
 
@@ -2,18 +2,22 @@
2
2
  require File.expand_path('../lib/active_admin_import/version', __FILE__)
3
3
 
4
4
  Gem::Specification.new do |gem|
5
- gem.authors = ["Igor Fedoronchuk"]
6
- gem.email = ["fedoronchuk@gmail.com"]
7
- gem.description = "The most efficient way to import for Active Admin"
8
- gem.summary = "ActiveAdmin import based on activerecord-import gem."
9
- gem.homepage = "http://github.com/Fivell/active_admin_import"
10
-
11
- gem.files = `git ls-files`.split($\)
12
- gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
- gem.name = "active_admin_import"
5
+ gem.authors = ["Igor Fedoronchuk"]
6
+ gem.email = ["fedoronchuk@gmail.com"]
7
+ gem.description = "The most efficient way to import for Active Admin"
8
+ gem.summary = "ActiveAdmin import based on activerecord-import gem."
9
+ gem.homepage = "http://github.com/Fivell/active_admin_import"
10
+ gem.license = 'MIT'
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "active_admin_import"
15
15
  gem.require_paths = ["lib"]
16
- gem.version = ActiveAdminImport::VERSION
16
+ gem.version = ActiveAdminImport::VERSION << '.rc1'
17
+
18
+ gem.add_runtime_dependency 'activerecord-import', '~> 0.4', '>= 0.4.1'
19
+ gem.add_runtime_dependency 'activeadmin', '~> 0.6', '>= 0.6.0'
20
+ gem.add_runtime_dependency 'zip', '~> 1.0', '>= 1.0.0'
21
+
17
22
 
18
- gem.add_runtime_dependency('activerecord-import','0.3.0')
19
23
  end
@@ -1,11 +1,11 @@
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| %>
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
5
  <%= f.inputs do %>
6
- <%= f.input :file, :as=>:file %>
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")} %>
7
10
  <% 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
11
  <% end %>
@@ -1,12 +1,12 @@
1
1
  module ActiveAdminImport
2
2
  module DSL
3
-
4
-
5
3
  # Declares import functionality
6
4
  #
7
5
  # Options
8
6
  # +back+:: resource action to redirect after processing
9
- # +col_sep+:: column separator used for CSV parsing
7
+ # +col_sep+:: column separator used for CSV parsing (deprecated)
8
+ # +row_sep+:: column separator used for CSV parsing (deprecated)
9
+ # +csv_options+:: hash to override default CSV options
10
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
12
  # +before_import+:: proc for before import action, hook called with importer object
@@ -15,83 +15,64 @@ module ActiveAdminImport
15
15
  # +after_batch_import+:: proc for after each batch action, called with importer object
16
16
  # +on_duplicate_key_update+:: an Array or Hash, tells activerecord-import to use MySQL's ON DUPLICATE KEY UPDATE ability.
17
17
  # +timestamps+:: true|false, tells activerecord-import to not add timestamps (if false) even if record timestamps is disabled in ActiveRecord::Base
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
18
+ # +ignore+:: true|false, tells activerecord-import to use MySQL's INSERT IGNORE ability
20
19
  # +template+:: custom template rendering
21
20
  # +template_object+:: object passing to view
22
- # +resource_class+:: resource class name
23
- # +resource_label+:: resource label value
21
+ # +resource_class+:: resource class name, override to import to another table (default config.resource_class)
22
+ # +resource_label+:: resource label value (default config.resource_label)
23
+ # +plural_resource_label+:: plaralized resource label value (default config.plural_resource_label)
24
24
  #
25
25
  def active_admin_import options = {}
26
26
  default_options = {
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
-
27
+ back: {action: :import},
28
+ csv_options: {},
29
+ template: "admin/import",
30
+ fetch_extra_options_from_params: [],
31
+ resource_class: config.resource_class,
32
+ resource_label: config.resource_label,
33
+ plural_resource_label: config.plural_resource_label,
34
+ headers_rewrites: {}
37
35
  }
38
- options = default_options.merge(options)
36
+ options = default_options.deep_merge(options)
37
+ options[:template_object] = ActiveAdminImport::Model.new if options[:template_object].blank?
39
38
  params_key = ActiveModel::Naming.param_key(options[:template_object])
40
39
 
41
-
42
- collection_action :import, :method => :get do
40
+ collection_action :import, method: :get do
43
41
  @active_admin_import_model = options[:template_object]
44
- render :template => options[:template]
42
+ render template: options[:template]
45
43
  end
46
44
 
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')
45
+ action_item only: :index do
46
+ link_to(I18n.t('active_admin_import.import_model', model: options[:resource_label]), action: 'import')
52
47
  end
53
48
 
49
+ collection_action :do_import, method: :post do
54
50
 
55
- collection_action :do_import, :method => :post do
56
- if params[params_key].blank?
57
- flash[:alert] = I18n.t('active_admin_import.no_file_error')
58
- return redirect_to :back
59
- end
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
71
- end
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])
51
+ @active_admin_import_model = options[:template_object]
52
+ @active_admin_import_model.assign_attributes(params[params_key].try(:deep_symbolize_keys) || {})
53
+ #go back to form
54
+ return render template: options[:template] unless @active_admin_import_model.valid?
55
+
56
+ importer = Importer.new(options[:resource_class],
57
+ @active_admin_import_model,
58
+ options
77
59
  )
78
60
  result = importer.import
79
-
61
+ model_name = options[:resource_label].downcase
62
+ plural_model_name = options[:resource_label].downcase
80
63
  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
64
+ count: result[:imported].to_i,
65
+ model: model_name,
66
+ plural_model: plural_model_name
67
+ ) if result[:imported].to_i > 0
86
68
 
87
69
  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
91
-
70
+ count: result[:failed].count,
71
+ model: model_name,
72
+ plural_model: plural_model_name
92
73
  ) if result[:failed].count > 0
93
74
 
94
- redirect_to :action => options[:back]
75
+ redirect_to options[:back]
95
76
  end
96
77
 
97
78
  end
@@ -2,65 +2,68 @@ require 'csv'
2
2
  module ActiveAdminImport
3
3
  class Importer
4
4
 
5
- attr_reader :resource, :file, :options , :extra_options , :result ,
6
- :cycle_data, :headers , :csv_lines
5
+ attr_reader :resource, :options, :result, :headers, :csv_lines, :model
7
6
 
8
7
  def store
9
8
  result = @resource.transaction do
10
9
  options[:before_batch_import].call(self) if options[:before_batch_import].is_a?(Proc)
11
10
 
12
-
13
11
  result = resource.import headers.values, csv_lines, {
14
- :validate => options[:validate],
15
- :on_duplicate_key_update => options[:on_duplicate_key_update],
16
- :ignore => options[:ignore],
17
- :timestamps => options[:timestamps]
12
+ validate: options[:validate],
13
+ on_duplicate_key_update: options[:on_duplicate_key_update],
14
+ ignore: options[:ignore],
15
+ timestamps: options[:timestamps]
18
16
  }
19
17
  options[:after_batch_import].call(self) if options[:after_batch_import].is_a?(Proc)
20
18
  result
21
19
  end
22
- {:imported => csv_lines.count - result.failed_instances.count , :failed => result.failed_instances}
20
+ {imported: csv_lines.count - result.failed_instances.count, failed: result.failed_instances}
23
21
  end
24
22
 
23
+ #
25
24
  def prepare_headers(headers)
26
- @headers = Hash[headers.zip(headers.map { |el| el.underscore.gsub(/\s+/, '_') })]
25
+ @headers = Hash[headers.zip(headers.map { |el| el.underscore.gsub(/\s+/, '_') })]
27
26
  @headers.merge!(options[:headers_rewrites])
28
27
  @headers
29
28
  end
30
29
 
31
- def initialize resource, file, options , extra_options = nil
30
+ def initialize(resource, model, options)
32
31
  @resource = resource
33
- @file = file
34
- @options = {
35
- :col_sep => ',',
36
- :batch_size => 1000,
37
- :validate => true
38
- }.merge(options)
39
- @headers = []
40
- @result= {
41
- :failed => [],
42
- :imported => 0
43
- }
44
- @extra_options = extra_options
45
- @csv_options = @options.slice(:col_sep, :row_sep)
32
+ @model = model
33
+ @options = {batch_size: 1000, validate: true}.merge(options)
34
+ @headers = model.respond_to?(:csv_headers) ? model.csv_headers : []
35
+ @result= {failed: [], imported: 0}
36
+ if @options.has_key?(:col_sep) || @options.has_key?(:row_sep)
37
+ ActiveSupport::Deprecation.warn "row_sep and col_sep options are deprecated, use csv_options to override default CSV options"
38
+ @csv_options = @options.slice(:col_sep, :row_sep)
39
+ else
40
+ @csv_options = @options[:csv_options] || {}
41
+ end
42
+ #override csv options from model if it respond_to csv_options
43
+ @csv_options = model.csv_options if model.respond_to?(:csv_options)
44
+ @csv_options.reject! {| key, value | value.blank? }
45
+
46
+ end
47
+
48
+ def file
49
+ @model.file
46
50
  end
47
51
 
48
52
  def cycle(lines)
49
- @csv_lines = CSV.parse(lines.join, @csv_options)
50
- @result.merge!(self.store){|key,val1,val2| val1+val2}
53
+ @csv_lines = CSV.parse(lines.join, @csv_options)
54
+ @result.merge!(self.store) { |key, val1, val2| val1+val2 }
51
55
  end
52
56
 
53
57
  def import
54
58
  options[:before_import].call(self) if options[:before_import].is_a?(Proc)
55
59
  lines = []
56
60
  batch_size = options[:batch_size].to_i
57
- IO.foreach(file.path) do |line|
58
- next if line.blank?
59
- if headers.empty?
60
- prepare_headers(CSV.parse(line, @csv_options).first)
61
- else
61
+ File.open(file.path) do |f|
62
+ # capture headers if not exist
63
+ prepare_headers(headers.any? ? headers : CSV.parse(f.readline, @csv_options).first)
64
+ f.each_line do |line|
62
65
  lines << line
63
- if lines.size >= batch_size
66
+ if lines.size == batch_size || f.eof?
64
67
  cycle lines
65
68
  lines = []
66
69
  end
@@ -2,26 +2,120 @@ module ActiveAdminImport
2
2
  class Model
3
3
  extend ActiveModel::Naming
4
4
  include ActiveModel::Conversion
5
-
6
- attr_accessor :file
7
- attr_accessor :hint
5
+ include ActiveModel::Validations
6
+ include ActiveModel::Validations::Callbacks
7
+
8
+ validates :file, presence: {message: Proc.new { I18n.t('active_admin_import.no_file_error') }},
9
+ unless: proc { |me| me.new_record? }
10
+
11
+ validate :correct_content_type
12
+
13
+ before_validation :uncompress_file, if: proc { |me| me.archive? && me.allow_archive? }
14
+ before_validation :encode_file, if: proc { |me| me.force_encoding? && me.file.present? }
15
+
8
16
  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
17
+
18
+ def initialize(args={})
19
+ @new_record = true
20
+ @attributes = {}
21
+ assign_attributes(default_attributes.merge(args), true)
22
+ end
23
+
24
+ def assign_attributes(args = {}, new_record = false)
25
+ @attributes.merge!(args)
26
+ @new_record = new_record
27
+ args.keys.each do |key|
28
+ key = key.to_sym
29
+ #generate methods for instance object by attributes
30
+ singleton_class.class_eval do
31
+ define_method(key) { self.attributes[key] } unless method_defined? key
32
+ define_method("#{key}=") { |new_value| @attributes[key] = new_value } unless method_defined? "#{key}="
19
33
  end
34
+ end if args.is_a?(Hash)
35
+ end
36
+
37
+ def read_attribute_for_validation(key)
38
+ @attributes[key.to_sym]
39
+ end
40
+
41
+ def default_attributes
42
+ {hint: '', file: nil, csv_headers: [], allow_archive: true, force_encoding: 'UTF-8'}
43
+ end
44
+
45
+ def allow_archive?
46
+ !!@attributes[:allow_archive]
47
+ end
48
+
49
+ def new_record?
50
+ !!@new_record
51
+ end
52
+
53
+ def force_encoding?
54
+ !!@attributes[:force_encoding]
55
+ end
56
+
57
+ def to_hash
58
+ @attributes
20
59
  end
21
60
 
22
61
  def persisted?
23
62
  false
24
63
  end
25
64
 
65
+ def archive?
66
+ file_type == 'application/zip'
67
+ end
68
+
69
+ protected
70
+
71
+ def file_path
72
+ if file.is_a? ActionDispatch::Http::UploadedFile
73
+ file.tempfile.path
74
+ else
75
+ file.path
76
+ end
77
+ end
78
+
79
+ def encode_file
80
+ data = File.read(file_path).encode(force_encoding, invalid: :replace, undef: :replace)
81
+ File.open(file_path, 'w') do |f|
82
+ f.write(data)
83
+ end
84
+ end
85
+
86
+ def uncompress_file
87
+ Zip::ZipFile.open(file_path) do |zip_file|
88
+ self.file = Tempfile.new("active-admin-import-unzipped")
89
+ data = zip_file.entries.select { |f| f.file? }.first.get_input_stream.read
90
+ data = data.encode(force_encoding, invalid: :replace, undef: :replace) if self.force_encoding?
91
+ self.file << data
92
+ self.file.close
93
+ end
94
+ end
95
+
96
+
97
+ def csv_allowed_types
98
+ [
99
+ 'text/csv',
100
+ 'text/x-csv',
101
+ 'text/comma-separated-values',
102
+ 'application/csv',
103
+ 'application/vnd.ms-excel',
104
+ 'application/vnd.msexcel'
105
+ ]
106
+ end
107
+
108
+
109
+ def correct_content_type
110
+ unless file.blank? || file.is_a?(Tempfile)
111
+ errors.add(:file, I18n.t('active_admin_import.file_format_error')) unless csv_allowed_types.include? file_type
112
+ end
113
+ end
114
+
115
+ def file_type
116
+ file.try(:content_type).try(:chomp)
117
+ end
26
118
  end
27
119
  end
120
+
121
+
@@ -1,3 +1,3 @@
1
1
  module ActiveAdminImport
2
- VERSION = "2.0.1"
2
+ VERSION = "2.1.0"
3
3
  end
metadata CHANGED
@@ -1,27 +1,75 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_admin_import
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
5
- prerelease:
4
+ version: 2.1.0.rc1
6
5
  platform: ruby
7
6
  authors:
8
7
  - Igor Fedoronchuk
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-09-11 00:00:00.000000000 Z
11
+ date: 2014-01-09 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: activerecord-import
16
- requirement: &70227838555100 !ruby/object:Gem::Requirement
17
- none: false
15
+ requirement: !ruby/object:Gem::Requirement
18
16
  requirements:
19
- - - =
17
+ - - ~>
20
18
  - !ruby/object:Gem::Version
21
- version: 0.3.0
19
+ version: '0.4'
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: 0.4.1
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '0.4'
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 0.4.1
33
+ - !ruby/object:Gem::Dependency
34
+ name: activeadmin
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ~>
38
+ - !ruby/object:Gem::Version
39
+ version: '0.6'
40
+ - - ! '>='
41
+ - !ruby/object:Gem::Version
42
+ version: 0.6.0
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ~>
48
+ - !ruby/object:Gem::Version
49
+ version: '0.6'
50
+ - - ! '>='
51
+ - !ruby/object:Gem::Version
52
+ version: 0.6.0
53
+ - !ruby/object:Gem::Dependency
54
+ name: zip
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ~>
58
+ - !ruby/object:Gem::Version
59
+ version: '1.0'
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: 1.0.0
22
63
  type: :runtime
23
64
  prerelease: false
24
- version_requirements: *70227838555100
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '1.0'
70
+ - - ! '>='
71
+ - !ruby/object:Gem::Version
72
+ version: 1.0.0
25
73
  description: The most efficient way to import for Active Admin
26
74
  email:
27
75
  - fedoronchuk@gmail.com
@@ -45,28 +93,28 @@ files:
45
93
  - lib/active_admin_import/model.rb
46
94
  - lib/active_admin_import/version.rb
47
95
  homepage: http://github.com/Fivell/active_admin_import
48
- licenses: []
96
+ licenses:
97
+ - MIT
98
+ metadata: {}
49
99
  post_install_message:
50
100
  rdoc_options: []
51
101
  require_paths:
52
102
  - lib
53
103
  required_ruby_version: !ruby/object:Gem::Requirement
54
- none: false
55
104
  requirements:
56
105
  - - ! '>='
57
106
  - !ruby/object:Gem::Version
58
107
  version: '0'
59
108
  required_rubygems_version: !ruby/object:Gem::Requirement
60
- none: false
61
109
  requirements:
62
- - - ! '>='
110
+ - - ! '>'
63
111
  - !ruby/object:Gem::Version
64
- version: '0'
112
+ version: 1.3.1
65
113
  requirements: []
66
114
  rubyforge_project:
67
- rubygems_version: 1.8.17
115
+ rubygems_version: 2.2.0
68
116
  signing_key:
69
- specification_version: 3
117
+ specification_version: 4
70
118
  summary: ActiveAdmin import based on activerecord-import gem.
71
119
  test_files: []
72
120
  has_rdoc: