Импорт из Excel в Rails

132
Импорт из Excel в Rails
Импорт из Excel в Rails

Как импортировать данные из файла Excel в Rails

Импорт из Excel в Rails с помощью roo gem.

Недавно мне пришлось это сделать по работе и я был удивлен тем, насколько это просто, поэтому и решил написать об этом статью.

Настройка демо проекта

Чтобы сделать все максимально понятным и простым, я просто импортирую пользователей.

Таблица пользователей выглядит следующим образом:

create_table "users", force: :cascade do |t|
  t.string "firstname"
  t.string "lastname", null: false
  t.string "username", null: false
  t.string "email", null: false
  t.integer "age"
  t.datetime "created_at", precision: 6, null: false
  t.datetime "updated_at", precision: 6, null: false
  t.index ["username"], name: "index_users_on_username", unique: true
end

users table in schema.rb

Импорт данных из файла Excel

Создайте файл

Очевидно, что для работы вам нужен файл Excel. Если у вас нет Microsoft Office 365, то просто используйте Google Sheets и загрузите его в виде файла Excel (именно так я это сделал).

Каждый столбец соответствует строке в вашей базе данных. Тот, который я буду использовать, выглядит следующим образом:

Как импортировать данные из файла Excel в Rails
Как импортировать данные из файла Excel в Rails

Устанавливаем gem

Добавьте gem в свой Gemfile и запустите bundle install.

gem "roo", "~> 2.9.0"

(Или любую другую текущую версию)

Создайте метод импорта

Готовый метод выглядит следующим образом и находится внутри UsersController.rb :

def import_data(path)
  xlsx = Roo::Spreadsheet.open(path[:xlsx_path])
  xlsx.sheet(0).each_with_index(firstname: 'First name', lastname: 'Surname', 
                                username: 'Username', email: 'E-Mail', age: 'Age') do |row, row_index|
                                
      next if row_index == 0 || User.find_by(username: row[:username]).present?

      User.create(
          firstname: row[:firstname],
          lastname: row[:lastname],
          username: row[:username],
          email: row[:email],
          age: row[:age]
      )
  end
end

Давайте пройдемся по нему шаг за шагом:

Первая строка открывает файл и делает его доступным для нас. Путь xlsx_path будет объяснен позже в разделе.

xlsx = Roo::Spreadsheet.open(path[:xlsx_path])

Затем он выбирает первый лист и перебирает строки. Круглые скобки не обязательны, я просто думаю, что так он будет более читабельным.

Без скобок row был бы простым массивом со значениями строки. Доступ к записям можно было бы получить, написав row[x]. Это быстро бы запутало, потому что я не думаю, что row[8] имеет большой смысл.

Со скобками создается хэш, что, на мой взгляд, делает его более читабельным.

xlsx.sheet(0).each_with_index(firstname: 'First name', lastname: 'Surname', username: 'Username', email: 'E-Mail', age: 'Age') do |row, row_index|
  stuff..
end

Далее мы пропускаем первую строку, поскольку это только заголовки, а также переходим к следующей строке, если пользователь с таким именем уже существует.

next if row_index == 0 || User.find_by(username: row[:username]).present?

Наконец, мы создаем нового пользователя с помощью полученной информации.

User.create(
  firstname: row[:firstname],
  lastname: row[:lastname],
  username: row[:username],
  email: row[:email],
  age: row[:age]
)

Создайте задачу rake для запуска метода

Запустите генератор для создания задачи rake:

rails g task import user_data

В качестве аргумента вы передадите путь к файлу .xlsx. Внутри задачи мы вызываем метод import_data и передаем ему путь:

namespace :import do
    desc 'Uploads data from xlsx'

    task :user_data, [:xlsx_path] => :environment do |_t, args|
        users_controller = UsersController.new
        users_controller.import_data(xlsx_path: args[:xlsx_path])
    end
end

Команда для запуска задачи rake выглядит следующим образом:

rake import:user_data['path']

И все! Импорт из Excel в Rails намного проще, чем я думал вначале.