Я пытаюсь создать набор моделей, который представляет собой набор продуктов. Когда я создаю новый комплект, я хотел бы проверить, существует ли соответствующий комплект, чтобы я мог его повторно использовать.
Модели
class Bundle < ApplicationRecord
has_and_belongs_to_many :products
end
class Product < ApplicationRecord
has_and_belongs_to_many :bundles
end
Миграция
class CreateBundles < ActiveRecord::Migration[5.2]
def change
create_table :bundles
create_table :products
create_join_table :bundles, :products
add_index :bundles_products, [:bundle_id, :product_id], unique: true
end
end
Что я пробовал
Сначала я попытался использовать find_or_create_by
, но ему не понравилась ассоциация HABTM:
Bundle.find_or_create_by!(products: Product.where(id: [1, 2, 3]))
# ActiveRecord::UnknownPrimaryKey (Unknown primary key for table bundles_products in model Bundles::HABTM_Products.)
На основании некоторых других вопросов, которые мне удалось создать несколько методов, которые достигают того же поведения, что и я. Это работает, но, учитывая, насколько это ужасно выглядит, это, безусловно, неправильный путь:
class Bundle < ApplicationRecord
has_and_belongs_to_many :products
def self.containing_exactly(products)
product_ids = products.pluck(:id)
where('bundles.id = (
SELECT bundles_products.bundle_id
FROM bundles_products
JOIN products on bundles_products.product_id = products.id
GROUP BY bundles_products.bundle_id
HAVING COUNT(DISTINCT CASE WHEN products.id IN (?) THEN products.id END) = ?
AND COUNT(CASE WHEN products.id NOT IN (?) THEN 1 END) = 0
LIMIT 1)', product_ids, product_ids.size, product_ids).first
end
def self.create_for(products)
containing_exactly(products) || create!(products: products)
end
end
Bundle.create_for(Product.first(2)) # Creates a new bundle with the first two products
Bundle.create_for(Product.first(2)) # Returns the previous bundle since it has the exact same products
Есть ли более простой способ найти существующие пакеты, которые соответствуют определенному набору продуктов, или есть другой способ подойти эти модели?
Использование mysql для базы данных