Проверка рельсов на объединенном столе - PullRequest
0 голосов
/ 15 апреля 2020

У меня есть следующие модели:

Продукт (id, имя):

    has_many :prices

Цена_продукта (id, product_id, цена): Дело в том, что каждый продукт может иметь разные цены

    belongs_to :product

Подписка (id, имя):

    has_many :subscription_price_sets,
             foreign_key: :subscription_price_set_id,
             inverse_of: :subscription
    has_many :product_prices, through: :subscription_price_sets

Subscription_price_set (id, product_price_id, subscription_id):

    belongs_to :subscription,
               foreign_key: :subscription_id
    belongs_to :product_price,
               foreign_key: :product_price_id

Как сделать Я подтверждаю это, так что для данной подписки невозможно иметь продукт с двумя разными ценами?

Например:

У меня есть два продукта: Записная книжка (id : 1) и Карандаш (id: 2) И их цены:

Цена продукта:

(id: 1, product_id: 1, price: 4)
(id: 2, product_id: 1, price: 12)
(id: 3, product_id: 1, price: 10)
(id: 4, product_id: 2, price: 3)
(id: 5, product_id: 2, price: 2)

И подписка Basi c:

(id: 1, name: "Basic")

Допустим, у меня есть Subscription_price_set:

(id: 1, product_price_id: 1, subscription_id: 1)

Теперь я должен иметь возможность создать еще один Subscription_price_set с subscription_id: 1, но единственными допустимыми product_price_ids должны быть id: 4 и id: 5 .

Есть какие-нибудь советы о том, как этого добиться?

1 Ответ

1 голос
/ 15 апреля 2020

Используйте scope для проверки уникальности нескольких столбцов:

validates_uniqueness_of :subscription_id, scope: :product_price_id

Однако это не гарантирует уникальность.

Image courtesy of Thoughtbot

Для защиты от состояния гонки вам необходимо дополнить проверку индексом базы данных:

class AddIndexToSubscriptionPriceSets < ActiveRecord::Migration[6.0]
  def change
    add_index :subscription_price_sets, [:subscription_id, :product_price_id] , unique: true
  end
end

Вы также неправильно используете опцию foreign_key. Rails управляется соглашением о конфигурации и извлекает внешний ключ из имени ассоциации. Вам нужно только указать foreign_key, если имя ассоциации не совпадает.

belongs_to :subscription
belongs_to :product_price

В ассоциации has_many это фактически приведет к ошибке:

has_many :subscription_price_sets,
         foreign_key: :subscription_price_set_id,
         inverse_of: :subscription

Это приведет к следующему соединению

JOINS subscription_price_sets ON subscription_price_sets.subscription_price_set_id = subscriptions.id

, которое, конечно, будет взорвано, поскольку такой колонки нет. Параметр foreign_key в ассоциации has_many используется для указания того, какой столбец в другой таблице соответствует этой таблице. Все, что вам действительно нужно, это:

has_many :subscription_price_sets

Rails также может выводить инверсию, основанную на ассоциации, и вам нужно только указать, когда вы «сходите с рельсов» и имена не совпадают.

...