2014-04-15 9 views
7

Korzystając z ruby ​​na szynach, mam tabelę klientów, do której chcę mieć możliwość dodawania nieograniczonych właściwości (par wartości klucza). Nie jestem pewien, jakie będą pary klucz/wartość, więc nie jestem pewien, jak to zrobić. Na przykład jeden klient może być:Nieograniczone dowolne właściwości (pary klucz/wartość) dla modelu ActiveRecord

  • klienta 1 Właściwości:
    • kolor: 'żółty'
    • marka: 'nike'
    • sprzedaży: '33'
  • klientów 2 właściwości:
    • kolor: "czerwony"
    • phone_numb ER: '1111111111'
    • zakupów: '2'

Zasadniczo, klienci mogą mieć dowolną liczbę właściwości pary klucz/wartość.

Jak mogę to zrobić?

Odpowiedz

1

Powinieneś być w stanie użyć do tego celu serialize i przypisać własności do twojego atrybutu właściwości i pobrać je w ten sam sposób.

+0

To jednak utrudni, jeśli nie uniemożliwi, zapytanie o te właściwości. –

+0

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/ –

+0

Tak, jeśli zainstalujesz klejnot. –

10

"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!

+0

Już uratowałeś mi kłopot - dobrze powiedziane! –

+0

Wow, świetna odpowiedź (ty też, brad). Użyłem serializacji, ale jest to również bardzo interesujące. wielkie dzięki –

+1

Czy ktoś wie o jakichkolwiek standardowych klejnotów Rails do korzystania z tego wzoru w wielu modelach Rails? –

1

Możesz zajrzeć do hydra_attribute gem, która jest implementacją wzorca Entity-Attribute-Value (EAV) dla modeli ActiveRecord.

Powiązane problemy