Как выполнить массовую вставку данных в таблицу с помощью Rails и одного оператора вставки

У меня есть следующие модели ActiveRecord, Widget, Merchant, Store, StoresWidget (ассоциация многих ко многим)

class Merchant < ActiveRecord::Base
  has_many :stores
  has_many :widgets
end

class Widget < ActiveRecord::Base
  has_many :stores_widgets
  has_many :stores, :through => :stores_widgets
  belongs_to :merchant
end

class Store < ActiveRecord::Base
  has_many :stores_widgets
  has_many :widgets, :through => :stores_widgets
  belongs_to :merchant
end

class StoresWidget < ActiveRecord::Base
  belongs_to :widget
  belongs_to :store
end

Таким образом, соответствующие таблицы widgets, merchants, stores а также stores_widgets, где widgets а также stores у каждого есть id столбец и stores_widgets имеет две колонки store_id а также widget_id, Виджет может быть доступен в 1 или более магазинах, а в магазине может быть доступно много виджетов. Некоторые виджеты доступны во всех магазинах, некоторые доступны только в подгруппе магазинов. Если виджет ограничен подмножеством магазинов, столбец restricted является true

Когда новый продавец добавляется к продавцу, я хочу обновить все неограниченные виджеты, которые будут связаны с этим магазином. В идеале я хотел бы иметь такой код в моем StoresController#create

class StoresController < ApplicationController
  def create
    # build new store...
    Store.transaction do
      store.save!
      Widget.update_all_unrestricted_widgets_with_store(store)
    end
    render :show
  end
end

куда update_all_unrestricted_widgets_with_store заканчивает выполнение SQL как:

INSERT INTO stores_widgets (store_id, widget_id) 
(SELECT #{store.id}, widgets.id 
 FROM widgets
 WHERE widgets.merchant_id = #{store.merchant_id} 
 AND widgets.restricted = FALSE)

Таким образом, если у продавца 100000 неограниченных виджетов, 100000 новых строк store_widgets создаются в одном INSERT, а не в 100000 отдельных INSERTS.

Предпочтительно я хотел бы получить ActiveRecord для создания вставки, как это. Это возможно? Если бы я не смог сделать это с ARel? Я хочу избежать выполнения строки SQL для достижения этой цели, если это возможно, чтобы я мог поддерживать уровень разделения кода и синтаксиса SQL базы данных.

1 ответ

Вы можете использовать activerecord-import реализует импорт AR#

activerecord-import - это библиотека для массовой вставки данных с использованием ActiveRecord.

посмотри, как это работает:

books = []
10.times do |i| 
  books << Book.new(:name => "book #{i}")
end
Book.import books

Ссылка - https://github.com/zdennis/activerecord-import

Другие вопросы по тегам