ruby-on-rails - 如何使用 smarter_csv 为 API 进行大规模创建 - Ruby on Rails
问题描述
如果怀疑是非常基本的,请原谅我,但我对此并不陌生。我喜欢它,但因为做家务,我几乎是一个人。
我在互联网上搜索了使用 smarter_csv gem FOR API 创建多个带有 CSV 文件的产品的示例,但我一无所获。
我真的不知道这是否与为 API 创建相同。
如果您能帮助我做任何事情,我将不胜感激。
我的表如下,我想在其中插入数据。
create_table "products", force: :cascade do |t|
t.string "sku"
t.string "origin_country"
t.string "hs_code"
t.integer "weight"
t.string "value"
t.string "description"
t.string "name"
t.string "category"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.bigint "seller_id"
t.string "width"
t.string "length"
t.string "height"
t.index ["seller_id"], name: "index_products_on_seller_id"
end
并在控制器中创建,如下所示:
def create
seller_id = @current_user.sellers.first.id
@product = Product.new(product_params.merge(seller_id: seller_id))
if @product.save
api_response({}, 'SUCCESS', ['Product created'])
else
api_response({}, 'ERROR', [@product.errors], 422)
end
end
还有路线,我知道也许就是这个
post '/product/upload', to: 'products#upload'
你对我有什么建议吗?
提前谢谢。
解决方案
由于处理 CSV 可能需要一段时间,您应该将其添加到处理队列并在后台处理它,您会立即使用队列中对象的 id 响应请求,用户可以稍后调用另一个 API具有该 id 的端点来检查处理的状态(或任何错误,如果有的话)。
您可以使用ActiveStorage之类的东西来存储上传的文件,并使用 delay_job 或 sidekiq 之类的东西在后台处理文件。您还需要将关联seller_id
的文件与文件及其状态一起存储。
由于您将处理 CSV 文件中的多条记录,因此您可能应该在事务中完成所有操作,以便任何错误都会导致所有其他保存回滚,然后用户可以修复并重新上传文件。在您的后台工作人员中:
Product.transaction do
queue_object.update!(status: 'PROCESSING', message: "Your CSV file is being processed.")
seller_id = queue_object.seller_id
seller = Seler.find(seller_id);
# I'm using the standard ruby CSV lib
CSV.foreach(queue_object.file_path, 'r', headers: true).with_index do |row, i|
# Call it with `!` so it raises an exception if validation fails, causing the transaction to rollback
seller.products.create!(
name: row['name'],
description: row['description'],
...
)
end
# Capture validation errors
rescue ActiveRecord::RecordInvalid => e
queue_object.update!(status: 'ERROR', message: "Error in row ##{i+1}: #{e.record.errors.to_json}")
raise # Re-raise the error so it stops the transaction
# This will be raised if the seller is not found
rescue ActiveRecord::RecordNotFound => e
queue_object.update!(status: 'ERROR', message: "Error in row ##{i+1}: #{e.message}")
raise
# All other exceptions
rescue => e
queue_object.update!(status: 'ERROR', message: "Error in row ##{i+1}: #{e.message}")
raise
else
# If there were no errors...
queue_object.update!(status: 'SUCCESS', message: 'File processed successfully')
ensure
# Delete the file here if you're not going to use it anymore
end
推荐阅读
- python-3.x - Pytest不同的测试目录和src目录
- npm - 电脑无法安装cpx
- android - 为什么要在 Android 中使用 Canvas?
- python - numpy:拆分具有不同起点的数组
- java - 制作一个包含来自另一个字符串数组的特定字母的数组(Java)
- google-analytics - Google Analytics 在尝试保存报告时出现“内部错误,请重试”
- javascript - 在 nextjs 中有多个动态导入
- java - 使用 Jackson 库将字符串转换为 Java 对象时,线程主 com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException 中的异常
- python - 将变量合并到命令语法中的最佳方法
- elasticsearch - 从浏览器禁用/隐藏弹性搜索默认端点访问