activeadminパネルからCSVファイルをアップロードしたい。
リソース「product」のインデックスページで、「importcsvfile」のある「newproduct」ボタンの横にボタンが必要です。
どこから始めればいいのかわからない。ドキュメントには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データをインポートできる人はいますか?
Thomas Watsonsからの続きは、残りの部分を理解する前に自分の方向性を理解するのに役立った答えへの素晴らしいスタートです。
コードブローでは、投稿モデルの例だけでなく、それ以降のモデルのCSVアップロードも可能です。必要なのは、action_itemと両方のcollection_actionsを例から他のActiveAdmin.registerブロックにコピーすることだけで、機能は同じになります。お役に立てれば。
app/admin/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
app/models/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
注:この例では、最初の列がID列であるかどうかを確認し、RailsがIDを割り当てるため、その列をスキップします。新しいオブジェクト(以下のCSVの例を参照してください)
app/views/admin/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'
app/public/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"
注:引用符は必ずしも必要ではありません
collection_action
を追加しても、そのアクションにリンクするボタンは自動的に追加されません。インデックス画面の上部にボタンを追加するには、次のコードをActiveAdmin.register
ブロックに追加する必要があります。
action_item :only => :index do
link_to 'Upload CSV', :action => 'upload_csv'
end
ただし、質問に投稿した収集アクションを呼び出す前に、まずユーザーがアップロードするファイルを指定する必要があります。私は個人的に別の画面でこれを行います(つまり、twoコレクションアクションを作成します-1つは:get
アクションで、もう1つは: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's 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
@krhorst、私はあなたのコードを使おうとしていましたが、残念ながらそれは大きなインポートを吸います。それはとても多くのメモリを消費します=(それで私はactiverecord-importgemに基づいた独自のソリューションを使用することにしました
ここにあります https://github.com/Fivell/active_admin_import
特徴
将来の参考のために、アクティブな管理リソースにcsvインポートを簡単に追加できるgemを作成しました
上記の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の答えが汚染されることは望ましくありませんでした。
通常の処理に時間がかかる大きなExcelの場合、アクティブなジョブを使用してExcelシートを処理し、アクションケーブル(websockets)を使用して結果を表示するgemを作成しました
私が非常に有用だと思ったben.mの応答を拡張します。
CSVインポートロジックに問題があり(属性が整列せず、列イテレーターが必要に応じて機能しない)、代わりに行ごとのループとmodel.createメソッドを使用する変更を実装しました。これにより、属性と一致するヘッダー行を持つ.csvをインポートできます。
app/models/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
上記の解決策のいくつかはかなりうまくいきました。私は実際に、以下で解決した課題に遭遇しました。解決された問題は次のとおりです。
注:作業中のIDを変更できるようにIDフィルターを削除しましたが、ほとんどのユースケースではおそらくそれを保持したいと考えています。
require 'csv'
class CsvDb
class << self
def convert_save(model_name, csv_data)
csv_file = csv_data.read
csv_file.to_s.force_encoding("UTF-8")
csv_file.sub!("\xEF\xBB\xBF", '')
target_model = model_name.classify.constantize
headers = csv_file.split("\n")[0].split(",")
CSV.parse(csv_file, headers: true) do |row|
new_object = target_model.new
column_iterator = -1
headers.each do |key|
column_iterator += 1
value = row[column_iterator]
new_object.send "#{key.chomp}=", value
end
new_object.save
end
ActiveRecord::Base.connection.reset_pk_sequence!(model_name.pluralize)
end
end
end