«Традиционный» способ сделать это — использовать шаблон 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 |
+----+-------------+--------------+------------+
Вам определенно понадобится INDEX для key
и возможно для value
(и, конечно, customer_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
). Если вы пойдете по этому пути, вы, вероятно, захотите определить некоторые удобные методы для клиента, чтобы сделать доступ и обновление свойств менее громоздкими. Я предполагаю, что, вероятно, есть жемчужины, специально предназначенные для того, чтобы шаблон EAV хорошо работал с ActiveRecord, но я не знаю их сразу, и я надеюсь, что вы простите меня за то, что я не гуглил, так как я мобилен.
Как указывает Брэд Верт, если вам нужно просто хранить произвольные свойства, а не запрашивать их, serialize
— отличная альтернатива, а если вы используете PostgreSQL, то даже проблема с запросами преодолима благодаря замечательной функции hstore.
Удачи!
person
Jordan Running
schedule
16.04.2014