Rails - проблема ассоциации для сложных моделей - PullRequest
0 голосов
/ 03 февраля 2020

У меня есть 3 таблицы.

product
product_attribute_mappings
product_attribute_values

Вот несколько строк каждой таблицы.

продукты

id  |name
1058|shoes

product_attribute_mappings

id  | product_id | product_attribute_id
438 | 1058       | 9

product_attribute_values ​​

id   | product_attribute_mapping_id | value
2001 | 438                          | 18 oz
2002 | 438                          | 19 oz

Как вы можете видеть здесь,

product.id = product_attribute_mappings.product_id
product_attribute_values.product_attribute_mapping_id = product_attribute_mappings.id

Я хочу получить весь продукт значения атрибутов, такие как

product.product_attribute_values # ["18 oz", "19 oz"]

Но я не уверен, как я могу сделать модели с ассоциациями, чтобы получить, как я хочу.

У кого-нибудь есть идеи?

Ответы [ 2 ]

1 голос
/ 03 февраля 2020

То, что у вас есть, является действительно странным обратным вариантом шаблона значения атрибута сущности (EAV). Было бы более разумно, если бы у вас были нормализованные определения атрибутов (например, объем, вес, количество рисунков и т. Д. c) в одной таблице и полномочия, атрибут и значение в одной таблице.

class Product < ApplicationRecord
  has_many :product_attributes
  has_many :product_attribute_types, through: :product_attributes
  # eager loading scope
  def self.eager_load_attributes
    eager_load(product_attributes: :product_attribute_types)
  end
end

# This is the normalization table that stores the definition of an attribute
# rails g model ProductAttribute name:string unit:string
class ProductAttributeType< ApplicationRecord
  has_many :product_attributes
  has_many :product_attribute_types, through: :product_attributes
end

# This is the actual table that defines the attributes
# rails g model ProductAttribute product:belongs_to product_attribute_type:belongs_to value:jsonb
class ProductAttribute < ApplicationRecord
  belongs_to :product # the entity
  belongs_to :product_attribute_type # the attribute
  # just shortcuts
  delegates :name, to: :product_attribute_type
  delegates :unit, to: :product_attribute_type
end

При этом в качестве значения используется столбец JSON, чтобы устранить одну из классических проблем с EAV, а именно то, что вам нужно привести все в один (обычно строковый) тип столбца. JSON может хранить числа (не очень хорошо), строки, массивы и объекты.

Это позволяет вам перебирать товары и атрибуты с помощью:

# eager loading avoids a n+1 query
@products = Product.eager_load_attributes.all

@products.each do |product|
   product.product_attributes.each do |attr|
     puts "#{attr.name}: #{attr.value}{attr.unit}"
   end
end
0 голосов
/ 03 февраля 2020

Вы можете изменить имя ассоциации с product_attribute_values на product_attribute_values_association, а затем определить product_attribute_values как методы экземпляра

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...