Tengo los siguientes modelos:
Producto (id, nombre):
has_many :prices
Product_price (id, product_id, price): La cuestión es que cada producto puede tener precios diferentes
belongs_to :product
Suscripción (id, nombre):
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, Subscribe_id):
belongs_to :subscription,
foreign_key: :subscription_id
belongs_to :product_price,
foreign_key: :product_price_id
¿Cómo lo valido, de modo que para una suscripción determinada es imposible tener un producto con dos precios diferentes?
Por ejemplo:
Tengo dos productos: Notebook (id: 1) y Pencil (id: 2) Y sus precios son:
Precios del producto:
(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)
Y una suscripción básica:
(id: 1, name: "Basic")
Digamos que tengo Subscription_price_set:
(id: 1, product_price_id: 1, subscription_id: 1)
Ahora debería poder crear otro Subscription_price_set
con subscription_id: 1
, pero los únicos product_price_ids permitidos deberían ser id: 4 e id: 5.
¿Alguna pista sobre cómo lograr eso?
2 respuestas
Creé un método de validación personalizado en el modelo Subscription_price_set
, y funcionó :)
validate :product_uniqness
private
def product_uniqness
return unless subscription.product_prices.pluck(:product_id)
.include?(product_price.product_id)
errors.add(:product_price_id, 'You can\'t add the same product twice')
end
Utilice scope
para realizar una validación de unicidad en varias columnas:
validates_uniqueness_of :subscription_id, scope: :product_price_id
Sin embargo, esto en realidad no garantiza la unicidad.
Para protegerse contra las condiciones de carrera, debe complementar la validación con un índice de base de datos:
class AddIndexToSubscriptionPriceSets < ActiveRecord::Migration[6.0]
def change
add_index :subscription_price_sets, [:subscription_id, :product_price_id] , unique: true
end
end
También estás usando la opción foreign_key
, todo está mal. Rails se maneja por convención sobre la configuración y derivará la clave foránea del nombre de la asociación. Solo necesita especificar foreign_key
si el nombre de la asociación no coincide.
belongs_to :subscription
belongs_to :product_price
En la asociación has_many
en realidad causará un error:
has_many :subscription_price_sets,
foreign_key: :subscription_price_set_id,
inverse_of: :subscription
Esto dará como resultado la siguiente unión
JOINS subscription_price_sets ON subscription_price_sets.subscription_price_set_id = subscriptions.id
Lo cual, por supuesto, explotará ya que no existe tal columna. La opción Foreign_key en una asociación has_many se usa para especificar qué columna en la otra tabla corresponde a esta tabla. Todo lo que realmente necesitas es:
has_many :subscription_price_sets
Los rieles también pueden deducir el inverso de una asociación basada y solo necesita especificar cuándo está "saliendo de los rieles" y los nombres no coinciden.
Preguntas relacionadas
Nuevas preguntas
ruby-on-rails
Ruby on Rails es un marco de aplicación web full-stack de código abierto escrito en Ruby. Sigue el popular modelo de marco MVC y es conocido por su enfoque de "convención sobre configuración" para el desarrollo de aplicaciones.