使用ActiveAdmin在Rails应用程序中导入CSV数据
我想通过activeadmin面板上传CSV文件 在资源“product”的索引页上,我希望在“new product”按钮旁边有一个带有“import csv file”的按钮 我不知道从哪里开始。 在文档中有一些关于collection_操作的内容,但是对于下面的代码,我在顶部没有链接使用ActiveAdmin在Rails应用程序中导入CSV数据,csv,ruby-on-rails-3.1,activeadmin,Csv,Ruby On Rails 3.1,Activeadmin,我想通过activeadmin面板上传CSV文件 在资源“product”的索引页上,我希望在“new product”按钮旁边有一个带有“import csv file”的按钮 我不知道从哪里开始。 在文档中有一些关于collection_操作的内容,但是对于下面的代码,我在顶部没有链接 ActiveAdmin.register Post do collection_action :import_csv, :method => :post do # Do some C
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数据的人?添加
集合\u操作
不会自动添加链接到该操作的按钮。要在索引屏幕顶部添加按钮,需要将以下代码添加到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'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
从托马斯·屈臣氏(Thomas Watsons)开始,继续回答这个问题,这个问题帮助我在了解其他问题之前了解了自己的方向 代码blow不仅允许对示例Posts模型进行CSV上传,还允许对随后的任何模型进行CSV上传。您只需将示例中的action_项和collection_操作复制到任何其他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
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
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
app/models/csv_db.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
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
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
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"
first_name,last_name,attribute1,attribute2
john,citizen,value1,value2
注意:引用并不总是需要的@krhorst,我正试图使用您的代码,但不幸的是,它对大的导入很糟糕。它消耗了大量内存=(因此我决定使用自己的基于activerecord import gem的解决方案) 给你 特征
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
需要“csv”
CsvDb类
类true)do |行|
目标\u model.create(行到\u散列)
结束
救援异常=>e
Rails.logger.error e.消息
Rails.logger.error e.backtrace.join(“\n”)
结束
结束
结束
结束
虽然不是一个完整的答案,但我不希望我的更改会污染ben.m的答案,以防我做了一些非常错误的事情。扩展ben.m的回答,我发现这非常有用 我遇到了CSV导入逻辑的问题(属性未对齐,列迭代器未按要求运行),并实现了一个更改,它使用了每行循环和model.create方法。这允许您导入标题行与属性匹配的.csv app/models/csv_db.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
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
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
对于在正常过程中需要时间的大型excel,我创建了一个gem,它使用活动工单处理excel工作表,并使用操作电缆(WebSocket)显示结果
上面的一些解决方案效果很好。我在实践中遇到了一些挑战,我在下面解决了这些挑战。解决的问题是:
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
需要“csv”
CsvDb类
为csv_db块初始化是否将模型_名称、目标_模型和新_对象替换为Post或Lead等相对名称?调用CsvDb时不需要简单地进行转换。转换_save(“Post”,params[:dump][:file])只需使用您喜欢的资源替换Post。如何覆盖任何现有条目?我得到一个SQLite3::ConstraintException:如果我试图在现有记录上导入CSV,则主键必须是唯一的
错误。问题出在Id上。您可以按照if id==something.id something.update_attributes:blah=>“blah”end的行插入一个条件语句