active_admin_import 2.0.1 → 2.1.0.rc1

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 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: