首页 > 解决方案 > 如何使用 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'

你对我有什么建议吗?

提前谢谢。

标签: ruby-on-railsrubyapi

解决方案


由于处理 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

推荐阅读