"Tradycyjny" sposób to zrobić za pomocą wzoru wartości elementu lub wzorca EAV. Jak sugeruje nazwa, utworzysz nową tabelę z trzema kolumnami: jedną dla "encji", która w tym przypadku jest klientem, jedna dla "atrybutu" nazwa lub klucz, a druga dla wartości. Więc chcesz mieć tabeli tak:
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 |
+----+-------------+--------------+------------+
Będziesz na pewno chcesz indeksu na key
i być może na value
(i customer_id
, oczywiście, ale Rails zrobi to za ciebie podczas korzystania relation
lub belongs_to
podczas migracji).
Następnie w modelach:
# customer.rb
class Customer < ActiveRecord::Base
has_many :customer_properties
end
# customer_property.rb
class CustomerProperty < ActiveRecord::Base
belongs_to :customer
end
Umożliwia to wykorzystanie tak:
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", ...>
Jako projekt bazy danych idzie to całkiem solidne, ale jak widać to ma pewne ograniczenia: W szczególności , jest uciążliwe. Ponadto użytkownik jest ograniczony do jednego typu wartości (często występuje :string
/VARCHAR
). Jeśli wybierzesz tę trasę, prawdopodobnie będziesz chciał zdefiniować pewne metody wygody dla Klienta, aby uzyskać dostęp i aktualizować właściwości mniej uciążliwe. Zgaduję, że są prawdopodobnie klejnoty specjalnie do tego, aby wzór EAV działał dobrze z ActiveRecord, ale nie znam ich z góry i mam nadzieję, że wybaczycie mi, że nie szukam go, ponieważ jestem mobilny.
Jak Brad Werth zwraca uwagę, jeśli wystarczy do przechowywania dowolnych właściwości i nie zapytać o nich, serialize
jest doskonałą alternatywą, a jeśli używasz PostgreSQL nawet problem zapytań jest do pokonania dzięki wielką cechą hstore.
Powodzenia!
To jednak utrudni, jeśli nie uniemożliwi, zapytanie o te właściwości. –
To zależy od używanej bazy danych. Postgres obsługuje go z łatwością - http://travisjeffery.com/b/2012/02/using-postgress-hstore-with-rails/ –
Tak, jeśli zainstalujesz klejnot. –