簡體   English   中英

如何使用rails活動記錄批量插入所有嵌套屬性

[英]How to insert all the nested attributes in bulk using rails active record

我有這樣的報告 model :-

class Report < ActiveRecord::Base
  has_many :report_clients
  accepts_nested_attributes_for :report_clients, :reject_if => proc { |attributes| attributes['client_id'].blank? },  :allow_destroy => true
end

而報告客戶端 model 就像

class ReportClient < ActiveRecord::Base
  belongs_to :report
end

在創建報告時,我的參數結構將類似於

Report.create({name: params[:name],  report_clients_attributes: [{client_id: 1}, {client_id:2}]})

它將運行 1 個查詢以插入報告和 2 個查詢以插入 report_clients。

通常,我曾經針對每個報告插入 1000 個 report_clients,這會導致 1000 個 sql 查詢。

我知道,我可以通過編寫原始 sql 插入來解決使用批量插入的問題。 但想知道是否有任何其他方式/更好的方式來做到這一點。

經歷過類似的情況后,對於此類情況,有一個很棒的gem activerecord-import

report = Report.new(name: params[:name])
report.save_with_nested_attributes(report_clients_attributes)

report.rb

def save_with_nested_attributes(report_clients_attributes)
  report_clients_objects = []
  transaction do
    save!
    report_clients_attributes.each do |client_attributes|
      report_clients_objects << report_clients.new(client_attributes)      
    end
    ReportClient.import(report_clients_objects)
  end
end

gem Wiki中提到了許多其他方式來批量導入記錄。

希望有幫助!

正如我在這篇博文中更詳細地概述的那樣,您可以使用模型的autosave_associated_records_for_#{relation}方法的覆蓋來批量插入嵌套屬性。

class Report < ActiveRecord::Base
  has_many :report_clients

  accepts_nested_attributes_for :report_clients,
    allow_destroy: true,
    reject_if: :blank?

  def autosave_associated_records_for_report_clients 
    return if report_clients.empty?

    ReportClient.insert_all(
      report_clients.map { |r| { report_id: id, client_id: r.client_id } },
      record_timestamps: true,
    )
  end 
end

默認情況下,這只會在:create上運行,但如果您將autosave: true添加到關系中,也可以用於:update 雖然您需要處理標記為marked_for_destruction? , 並相應地刪除它們,否則它將是僅插入的。 您可能還想查看upsert_all ,因為可以更新或跳過重復項。

另一件需要注意的是 model 驗證——它們不是用insert_all運行的。 記在腦子里。 您可能能夠手動運行 model 驗證,但批量插入最好與強大的數據庫約束一起使用。

最后——這是使用內部(即私有)Rails API,但它在 9 年內沒有改變。

您可以如下使用create

Report.create({name: params[:name],  report_clients: report_clients})

其中report_clients定義為

def report_clients
        clients = [{client_id: 1}, {client_id:2}]
        clients.map do |client|
          ReportClient.new(client)
        end
end

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM