Crie um processo de importação de dados em um trabalho em segundo plano

Para realizar este processo devemos adicionar as seguintes joias:
” ‘Ruby

jquery-fileupload-rails jQuery File Upload for Rails 3.1 Asset Pipeline (Rails 3.2 suportado)

gem “jquery-fileupload-rails”

Permite criar modelo de uploader para o processo de seleção de arquivos e indica quais extensões são permitidas

gem ‘carrierwave’, ‘~> 1.0’

Roo implementa acesso de leitura para todas as planilhas comuns no Excelx, OpenOffice e CSV

gem “roo”, “~> 2.7.0”

Adicionar formato de arquivo Roo Excel xls

gem ‘roo-xls’

Use sidekiq para trabalhos em segundo plano

gem ‘sidekiq’ ”

Crie alguns métodos no arquivo do controlador do usuário:

def importar usuários novo
final

def import users create
@user import = UserImport.new (
file: import
user params [: import users],
status: UserImport.statuses [“incomplete”]
)
@user import.save
BackgroundImporter.perform
async (@ user_import.id)
end

def import users poller
@user_import = UserImport.find (params [: id])
end

privado

def import user params
params.require (: importar arquivo) .permit (: importar usuários)

fim

No arquivo config / routes.rb, crie algumas rotas personalizadas para os controladores e a visualização de importação:

obtenha ‘import users / new’, to: ‘users # import users new’, as: ‘import users new’
post ‘import
users’, to: ‘users # import users create’, as: ‘import_users’

obtenha ‘import users poller /: id’, para: ‘users # import users poller’, como: ‘import users poller’

Defina a visualização de importação do usuário na pasta app / views / user / import users new.html.haml (em código haml):

.row
.col-md-12
/ aqui mostra as mensagens de sucesso ou erro para o upload do arquivo /
# upload-users-new
# upload-success.alert.alert-success.no-margin.messages
% span Sucesso no upload do arquivo
#upload -errors.alert.alert-danger.no-margin.messages

/  Shows the file upload button and the text for the file name   /
= link_to "Select File", "#", id: 'upload-launch', class: "btn btn-primary import-form"
%span#file-name No file selected...

/ Form for the import process this is hide /
.import-form.hidden
= form_for :import_file, url: import_users_path, multipart: true do |f|
= f.file_field :import_users, id: 'fileupload'
= submit_tag "file_import", id: 'import-submit'

/ Bar process did with a div and background color /
#progress
.bar
.bar-success

/ Animated gif to show the import process /
#import-process
%span
.load-text
Importing Data...
= image_tag "spinner.gif", class: "load-img"

/ here show the success or error messages for the users import process /
#import-success.sides-margin.alert.alert-success.no-margin.messages
%span Importing users successfully completed
#import-errors.sides-margin.alert.alert-danger.no-margin.messages
%span The user import failed contact the system administrator
#import-finished.messages
%span
.load-finished / Show button to return to the users list /
= link_to "Return Users", users_path, class: "btn btn-default btn-lg btn-block"

Neste template fazemos um formulário para fazer o processo de seleção de arquivos, para dar estilo ao formulário devemos esconder o formulário e o template um botão com um bootstrap e o nome do arquivo em um rótulo de texto e usar javascript para executar o processo

/ CSS para o usuário importar arquivo new.html.haml //

upload-users-new {

largura: 50%;
margem: automático;
margem superior: 10px;
preenchimento: 0px 5px;
borda: 1px sólido #ccc;
raio da borda: 10px;

# upload-success {
margin: 15px 15px 0px 15px;
padding-left: 20px;
Mostrar nenhum;
}
# upload-errors {
margin: 15px 15px 0px 15px;
padding-left: 20px;
Mostrar nenhum;
}

. formato de importação {
margin: 15px 15px;
}
.file-name {
display: inline-block;
preenchimento: 15px 15px;
}

#progress {
margin: 0px 15px 15px;
.bar {
largura: 100%;
altura: 18px;
plano de fundo: # e9e6e6;
raio da borda: 5px;
posição: relativa;
-webkit-box-shadow: inserção 0 1px 2px rgba (0,0,0, .1);
sombra da caixa: inserção 0 1px 2px rgba (0,0,0, .1);
.bar-success {
width: 0%;
altura: 18px;
plano de fundo: # 57b7d4;
raio da borda: 5px;
posição: absoluta;
}
}
}

# import-process {
width: 259px;
margem: automático;
Mostrar nenhum;
.load-text {
font-size: 26px;
família de fontes: cursiva;
display: bloco embutido;
margin-bottom: 15px;
cor: # a2a1a1;
.load-img {
largura: 30px;
altura: 30px;
display: bloco embutido;
}
}
}

.sides-margin {
margin: 0px 15px 15px;
}

# import-success {
display: none;
}

# import-errors {
display: none;
}

# importação concluída {
display: none;
.
carregamento concluído { margin: 15px 15px;
margin-bottom: 15px;
}
}

}

Código Javascript para o processo de importação (o código está em coffescript):

$ (‘# upload-launch’). click ->
$ (‘# upload-errors’). css (“display”, ‘none’)
$ (‘# upload-success’). css (“display”, ‘ none ‘)
$ (‘ # import-errors ‘). css (“display”,’ none ‘)
$ (‘ # import-ended ‘). css (“display”,’ none ‘)
$ (‘ # fileupload ‘) .fileupload
dataType: ‘json’
progressall: (e, data) ->
progress = parseInt (data.loaded / data.total * 100, 10)
$ (‘# progress .bar-success’). css ‘largura’, progresso + ‘%’
done: (e, data) ->
if data.result.errors
$ (‘# upload-errors’). css (“display”,’herdar’)
i = 0
enquanto i <data.result.errors.length
$ (‘# upload-errors’). append (“<span>” + data.result.errors [i] + “</span> </br>”);
i ++
else
$ (‘# upload-success’). css (“display”, ‘inherit’)
$ (‘# file-name’). text (data.result.name)
$ (‘# progress’). css ( “display”, ‘none’)
$ (‘# import-process’). css (“display”, ‘inherit’)
setInterval (->
$ .ajax
url: “/ admin / import users poller /” + data.result .id,
dataType: “json”
sucesso: ( dados
ajax , textStatus, jqXHR) ->
$ (‘# import-process’). css (“display”, ‘none’)
$ (‘# import-success’). css (“display”, ‘herdar’)
$ (‘# import-finalizado’). css (“display”, ‘inherit’)
if (ajax_data.status == “failed”)
$ (‘# import-process’). css (“display”, ‘none’)
$ (‘# import-errors’) .css (“display”, ‘inherit’)
$ (‘# import-ended’). css (“display”, ‘inherit’)
), 5000

$ (‘# fileupload’). click ()

Gere o modelo do Uploader com CarryWave e adicione na lista branca quais tipos de arquivos são permitidos:

classe UsersImportUploader <CarrierWave :: Uploader :: Base
def extension_whitelist
% w (xls xlsx ods)
end

fim

Crie uma nova classe para fazer todo o processo de importação, na pasta do modelo:

class UserImportManager
attr accessor: user import

def initialize (user import id)
@user import = UserImport.find (user import_id)
end

# Importar dados do arquivo para o banco de dados
def import
spreadsheet = open spreadsheet
header = spreadsheet.row (1)
(2..spreadsheet.last
row) .each do | i |
row = Hash [[header, spreadsheet.row (i)]. transpose]
@user = User.new (row)
@ user.save!
end
@user import.update atributos (status: UserImport.statuses [“complete”])
end

# Abra o arquivo de importação e detecte o arquivo de extensão
def abrir a planilha
caso File.extname (@user
import [: file])
quando “.csv” then :: Roo :: Csv.new (@user import.file.path, password: nil )
quando “.ods” then :: Roo :: OpenOffice.new (@user
import.file.path, password: nil)
quando “.xls” then :: Roo :: Excel.new (@user import.file.path , senha: nil)
quando “.xlsx” then :: Roo :: Excelx.new (@user
import.file.path, senha: nil)
else aumentar “Tipo de arquivo desconhecido: # {file.original_filename}”
end
end

fim

Na pasta do aplicativo, criamos uma pasta chamada workers onde criaremos uma classe onde o processo de importação será enviado para o trabalho em segundo plano:

classe BackgroundImporter
inclui Sidekiq :: Worker

def executar ( id de importação de usuário )
begin
User.transaction do
@import = UserImportManager.new ( id de importação de usuário )
@ import.import
end
rescue Exception => exeption msgs
@user
import = UserImport.find ( id de importação de usuário )
@user import. atualizar atributos (status: UserImport.statuses [“falhou”])
end
end
end