在rails上使用ruby,我有一个Customer表,我希望能够添加无限属性(键值对)。我不确定键/值对将是什么,所以我不知道如何做到这一点。例如,一个客户可能是:
基本上,客户可以在键/值对中拥有任意数量的属性。
我该怎么做?
答案 0 :(得分:11)
"传统"这样做的方法是使用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
上的INDEX和<{1}}上的 (以及value
,但Rails会这样做您在迁移中使用customer_id
或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: "foo@bar.com")
# => #<CustomerProperty id: 7, customer_id: 1, key: "email", ...>
/ :string
很常见)。如果你走这条路线,你可能想在Customer上定义一些便利方法,使访问和更新属性变得不那么麻烦。我猜测可能有专门用于使EAV模式与ActiveRecord很好地配合使用的宝石,但我不知道它们在我的头脑中,我希望你能原谅我没有使用谷歌搜索,因为我是移动电话。
正如Brad Werth所指出的,如果你只需要存储任意属性而不是通过它们查询,VARCHAR
是一个很好的选择,如果你使用PostgreSQL,即使查询问题是可以克服的,因为它有很棒的hstore功能
答案 1 :(得分:2)
您可能需要查看hydra_attribute gem,它是ActiveRecord模型的实体 - 属性 - 值(EAV)模式的实现。
答案 2 :(得分:1)
您应该可以使用serialize,并将属性哈希值分配给属性属性,并以相同的方式检索它们。