Неограничени произволни свойства (двойки ключ/стойност) за модел ActiveRecord

Използвайки ruby ​​on rails, имам таблица Customer, към която искам да мога да добавя неограничени свойства (двойки ключ стойност). Все още не съм сигурен какви ще бъдат двойките ключ/стойност, така че не съм сигурен как да направя това. Например, един клиент може да бъде:

  • Customer 1 properties:
    • color: 'yellow'
    • марка: "nike"
    • продажби: '33'
  • Customer 2 properties:
    • color: 'red'
    • телефонен_номер: '1111111111'
    • покупки: '2'

По принцип клиентите могат да имат произволен брой свойства в двойка ключ/стойност.

Как мога да направя това?


person Matthew Berman    schedule 15.04.2014    source източник


Отговори (3)


Трябва да можете да използвате serialize за това и да зададете хеш свойствата си към атрибута на вашите свойства и ги извлечете по същия начин.

person Brad Werth    schedule 15.04.2014
comment
Това обаче ще затрудни, ако не и невъзможно, заявките по тези свойства. - person Jordan Running; 17.04.2014
comment
Това зависи от използваната база данни. Postgres го поддържа лесно - travisjeffery.com/b/2012/ 02/using-postgress-hstore-with-rails - person Brad Werth; 17.04.2014
comment
Да, ако инсталирате скъпоценния камък. - person Jordan Running; 17.04.2014
comment
Това е трудно, ако не и невъзможно? Освен това Rails 4 го поддържа първоначално. Защо просто не посочихте, че може да изисква скъпоценния камък? - person Brad Werth; 17.04.2014
comment
Защото не знаех за скъпоценния камък и не всеки използва Postgres? Отговорът ви беше добър, с предупреждения - просто исках да се уверя, че OP знае едно от тези предупреждения. - person Jordan Running; 17.04.2014
comment
Точно така, те вероятно си струва да бъдат споменати в действителния отговор, поради причините, които споменавате... - person Brad Werth; 17.04.2014

„Традиционният“ начин да направите това е с модела Entity-Attribute-Value или EAV. Както подсказва името, ще създадете нова таблица с три колони: една за „субекта“, който в този случай е клиентът, една за името или ключа на „атрибута“ и една за стойността. Така че ще имате таблица като тази:

customer_properties
+----+-------------+--------------+------------+
| id | customer_id | key          | value      |
+----+-------------+--------------+------------+
|  1 |           1 | color        | yellow     |
|  2 |           1 | brand        | nike       |
|  3 |           1 | sales        | 33         |
|  4 |           2 | color        | red        |
|  5 |           2 | phone_number | 1111111111 |
|  6 |           2 | purchases    | 2          |
+----+-------------+--------------+------------+

Определено ще искате ИНДЕКС на key и може би на valuecustomer_id, разбира се, но Rails ще направи това вместо вас, когато използвате relation или belongs_to във вашата миграция).

След това във вашите модели:

# customer.rb
class Customer < ActiveRecord::Base
  has_many :customer_properties
end

# customer_property.rb
class CustomerProperty < ActiveRecord::Base
  belongs_to :customer
end

Това позволява използване по следния начин:

customer = Customer.joins(:customer_properties)
             .includes(:customer_properties)
             .where(customer_properties: { key: "brand", value: "nike" })
             .first

customer.customer_properties.each_with_object({}) do |prop, hsh|
  hsh[prop.key] = prop.val
end
# => { "color" => "yellow",
#      "brand" => "nike",
#      "sales" => "33" }

customer.customer_properties.create(key: "email", value: "[email protected]")
# => #<CustomerProperty id: 7, customer_id: 1, key: "email", ...>

Що се отнася до дизайна на базата данни, това е доста солидно, но както можете да видите, има някои ограничения: По-специално, това е тромаво. Освен това сте ограничени до един тип стойност (:string/VARCHAR е често срещано). Ако тръгнете по този път, вероятно ще искате да дефинирате някои удобни методи на Customer, за да направите достъпа и актуализирането на свойствата по-малко тромави. Предполагам, че вероятно има скъпоценни камъни специално за направата на шаблона EAV да работи добре с ActiveRecord, но не ги знам наизуст и се надявам да ми простите, че не гугълнах, тъй като съм мобилен.

Както отбелязва Брад Верт, ако просто трябва да съхранявате произволни свойства и да не правите заявки от тях, serialize е чудесна алтернатива, а ако използвате PostgreSQL дори проблемът със заявките е преодолим благодарение на страхотната му функция hstore.

Късмет!

person Jordan Running    schedule 16.04.2014
comment
Точно така, спестихте ми неприятностите - добре казано! - person Brad Werth; 17.04.2014
comment
Уау, страхотен отговор (ти също, Брад). Използвах сериализиране, но това също е много интересно. много благодаря - person Matthew Berman; 18.04.2014
comment
Някой знае ли за някакви стандартни Rails скъпоценни камъни за използване на този модел в множество Rails модели? - person Eric Walker; 09.09.2017

Може да искате да разгледате hydra_attribute gem, който е реализация на Entity-Attribute-Value ( EAV) модел за модели ActiveRecord.

person Javid Jamae    schedule 12.02.2015