lib/active_admin_import/dsl.rb
# frozen_string_literal: true
module ActiveAdminImport
# Declares import functionality
#
# Options
# +back+:: resource action to redirect after processing
# +csv_options+:: hash to override default CSV options
# +batch_size+:: integer value of max record count inserted by 1 query/transaction
# +batch_transaction+:: bool (false by default), if transaction is used when batch importing
# and works when :validate is set to true
# +before_import+:: proc for before import action, hook called with importer object
# +after_import+:: proc for after import action, hook called with importer object
# +before_batch_import+:: proc for before each batch action, called with importer object
# +after_batch_import+:: proc for after each batch action, called with importer object
# +validate+:: true|false, means perform validations or not
# +on_duplicate_key_update+:: an Array or Hash, tells activerecord-import
# to use MySQL's ON DUPLICATE KEY UPDATE ability.
# +timestamps+:: true|false, tells activerecord-import to not add timestamps (if false)
# even if record timestamps is disabled in ActiveRecord::Base
# +ignore+:: true|false, tells activerecord-import to use MySQL's INSERT IGNORE ability
# +template+:: custom template rendering
# +template_object+:: object passing to view
# +resource_class+:: resource class name, override to import to another table (default config.resource_class)
# +resource_label+:: resource label value (default config.resource_label)
# +plural_resource_label+:: pluralized resource label value (default config.plural_resource_label)
#
module DSL
DEFAULT_RESULT_PROC = lambda do |result, options|
model_name = options[:resource_label].downcase
plural_model_name = options[:plural_resource_label].downcase
if result.empty?
flash[:warning] = I18n.t('active_admin_import.file_empty_error')
else
if result.failed?
flash[:error] = I18n.t(
'active_admin_import.failed',
count: result.failed.count,
model: model_name,
plural_model: plural_model_name,
message: result.failed_message(limit: options[:error_limit]))
return if options[:batch_transaction]
end
if result.imported?
flash[:notice] = I18n.t(
'active_admin_import.imported',
count: result.imported_qty,
model: model_name,
plural_model: plural_model_name)
end
end
end
# rubocop:disable Metrics/AbcSize
def active_admin_import(options = {}, &block)
options.assert_valid_keys(*Options::VALID_OPTIONS)
options = Options.options_for(config, options)
collection_action :import, method: :get do
authorize!(ActiveAdminImport::Auth::IMPORT, active_admin_config.resource_class)
@active_admin_import_model = if options[:template_object].is_a?(Proc)
options[:template_object].call
else
options[:template_object]
end
render template: options[:template]
end
action_item :import, only: :index, if: options[:if] do
if authorized?(ActiveAdminImport::Auth::IMPORT, active_admin_config.resource_class)
link_to(
I18n.t('active_admin_import.import_model', plural_model: options[:plural_resource_label]),
action: :import
)
end
end
collection_action :do_import, method: :post do
authorize!(ActiveAdminImport::Auth::IMPORT, active_admin_config.resource_class)
_params = params.respond_to?(:to_unsafe_h) ? params.to_unsafe_h : params
params = ActiveSupport::HashWithIndifferentAccess.new _params
@active_admin_import_model = if options[:template_object].is_a?(Proc)
options[:template_object].call
else
options[:template_object]
end
params_key = ActiveModel::Naming.param_key(@active_admin_import_model.class)
@active_admin_import_model.assign_attributes(params[params_key].try(:deep_symbolize_keys) || {})
# go back to form
return render template: options[:template] unless @active_admin_import_model.valid?
@importer = Importer.new(
options[:resource_class],
@active_admin_import_model,
options
)
begin
result = @importer.import
if block_given?
instance_eval(&block)
else
instance_exec result, options, &DEFAULT_RESULT_PROC
end
rescue ActiveRecord::Import::MissingColumnError,
NoMethodError,
ArgumentError,
ActiveRecord::StatementInvalid,
CSV::MalformedCSVError,
ActiveAdminImport::Exception => e
Rails.logger.error(I18n.t('active_admin_import.file_error', message: e.message))
Rails.logger.error(e.backtrace.join("\n"))
flash[:error] = I18n.t('active_admin_import.file_error', message: e.message[0..200])
end
redirect_to options[:back]
end
# rubocop:enable Metrics/AbcSize
end
end
end