Подтвердить что ты не робот

Импорт данных CSV в приложение Rails с ActiveAdmin

Я хочу загрузить CSV файлы через панель activeadmin.

на странице индекса из ресурса "продукт", я хочу кнопку рядом с кнопкой "новый продукт" с "import csv file".

Я не знаю, с чего начать. в документации есть что-то о collection_action, но с приведенным ниже кодом у меня нет ссылки наверху.

ActiveAdmin.register Post do
    collection_action :import_csv, :method => :post do
      # Do some CSV importing work here...
      redirect_to :action => :index, :notice => "CSV imported successfully!"
    end
  end

кто-нибудь, кто использует activeadmin и может импортировать данные csv?

4b9b3361

Ответ 1

Продолжая с Thomas Watsons отличный ответ на этот вопрос, который помог мне разобраться, прежде чем выдумывать остальную часть.

Удар кода позволяет не только загружать CSV для модели Posts Posts, но и для последующих моделей. все, что вам нужно сделать, это скопировать action_item и оба коллекционных_извлечения из примера в любой другой блок ActiveAdmin.register, и функциональность будет одинаковой. надеюсь, что это поможет.

приложение/администратор/posts.rb

ActiveAdmin.register Post do
  action_item :only => :index do
    link_to 'Upload CSV', :action => 'upload_csv'
  end

  collection_action :upload_csv do
    render "admin/csv/upload_csv"
  end

  collection_action :import_csv, :method => :post do
    CsvDb.convert_save("post", params[:dump][:file])
    redirect_to :action => :index, :notice => "CSV imported successfully!"
  end

end

приложение/модели/csv_db.rb

require 'csv'
class CsvDb
  class << self
    def convert_save(model_name, csv_data)
      csv_file = csv_data.read
      CSV.parse(csv_file) do |row|
        target_model = model_name.classify.constantize
        new_object = target_model.new
        column_iterator = -1
        target_model.column_names.each do |key|
          column_iterator += 1
          unless key == "ID"
            value = row[column_iterator]
            new_object.send "#{key}=", value
          end
        end
        new_object.save
      end
    end
  end
end

note: в этом примере проверяется, является ли первый столбец столбцом идентификатора, а затем пропускает этот столбец, поскольку рельсы назначают идентификатор новому объекту (см. пример CSV ниже для справки)

приложение/просмотров/админ/CSV/upload_csv.html.haml

= form_for :dump, :url=>{:action=>"import_csv"}, :html => { :multipart => true } do |f|
  %table
    %tr
      %td
        %label{:for => "dump_file"}
          Select a CSV File :
      %td
        = f.file_field :file
    %tr
      %td
        = submit_tag 'Submit'

приложение/открытый/example.csv

"1","TITLE EXAMPLE","MESSAGE EXAMPLE","POSTED AT DATETIME"
"2","TITLE EXAMPLE","MESSAGE EXAMPLE","POSTED AT DATETIME"
"3","TITLE EXAMPLE","MESSAGE EXAMPLE","POSTED AT DATETIME"
"4","TITLE EXAMPLE","MESSAGE EXAMPLE","POSTED AT DATETIME"
"5","TITLE EXAMPLE","MESSAGE EXAMPLE","POSTED AT DATETIME"

Примечание: цитаты не всегда нужны

Ответ 2

Добавление collection_action не добавляет автоматически ссылку на это действие. Чтобы добавить кнопку в верхней части индексного экрана, вам нужно добавить следующий код в блок ActiveAdmin.register:

action_item :only => :index do
  link_to 'Upload CSV', :action => 'upload_csv'
end

Но прежде чем вызывать действие коллекции, опубликованное в вашем вопросе, вам сначала нужно указать, какой файл загрузить. Я лично сделал бы это на другом экране (т.е. Создав два действия коллекции - один из которых - это действие :get, а другое - ваше действие :post). Таким образом, полный контроллер AA будет выглядеть примерно так:

ActiveAdmin.register Post do
  action_item :only => :index do
    link_to 'Upload posts', :action => 'upload_csv'
  end

  collection_action :upload_csv do
    # The method defaults to :get
    # By default Active Admin will look for a view file with the same
    # name as the action, so you need to create your view at
    # app/views/admin/posts/upload_csv.html.haml (or .erb if that your weapon)
  end

  collection_action :import_csv, :method => :post do
    # Do some CSV importing work here...
    redirect_to :action => :index, :notice => "CSV imported successfully!"
  end
end

Ответ 3

@krhorst, я пытался использовать ваш код, но, к сожалению, он засасывает большие объемы импорта. Он питается так много памяти = (Поэтому я решил использовать собственное решение на основе атрибута activerecord-import

Здесь https://github.com/Fivell/active_admin_import

Функции

  • Обработка кодирования
  • Поддержка импорта с ZIP-архивом
  • Двухэтапный импорт (см. пример2)
  • Параметры CSV
  • Возможность автоматически добавлять заголовки CSV
  • Массовый импорт (activerecord-import)
  • Возможность настройки шаблона
  • Поддержка обратных вызовов
  • Поддержка импорта из zip файла
  • ....

Ответ 4

В будущем, я построил драгоценный камень, который позволяет вам легко добавлять импорт csv в активный ресурс admin

См. ссылку

Ответ 5

Основываясь на ben.m отличный ответ выше, я заменил раздел csv_db.rb, предложенный следующим образом:

require 'csv'
class CsvDb
  class << self
    def convert_save(model_name, csv_data)
      begin
        target_model = model_name.classify.constantize
        CSV.foreach(csv_data.path, :headers => true) do |row|
          target_model.create(row.to_hash)
        end
      rescue Exception => e
        Rails.logger.error e.message
        Rails.logger.error e.backtrace.join("\n")
      end
    end
  end
end

Хотя не полный ответ, я не хотел, чтобы мои изменения загрязняли ben.m ответ в случае, если я сделал что-то вопиющее неправильное.

Ответ 6

расширение на ben.m ответ, который я нашел очень полезным.

У меня возникли проблемы с логикой импорта CSV (атрибуты не выравниваются, и итератор столбца не работает по мере необходимости) и реализовал изменение, которое вместо этого использует цикл в каждой строке и метод model.create. Это позволяет импортировать CSV с строкой заголовка, соответствующей атрибутам.

приложение/модели/csv_db.rb

require 'csv'
class CsvDb
  class << self
    def convert_save(model_name, csv_data)
      csv_file = csv_data.read
      lines = CSV.parse(csv_file)
      header = lines.shift
      lines.each do |line|
        attributes = Hash[header.zip line]
        target_model = model_name.classify.constantize
        target_model.create(attributes)
      end
    end
  end
end

Итак, ваш импортированный CSV файл может выглядеть так (используйте для соответствия с атрибутами модели):

importExample.csv

first_name,last_name,attribute1,attribute2
john,citizen,value1,value2

Ответ 7

Для большого excel, требующего времени на нормальный процесс, я создал драгоценный камень, который обрабатывает листы Excel с использованием активного задания и отображает результаты с помощью кабеля действия (websockets)

https://github.com/shivgarg5676/active_admin_excel_upload