Как выполнить массовую вставку данных в таблицу с помощью 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