ActiveRecord模型的无限任意属性(键/值对)

时间:2014-04-15 22:37:24

标签: ruby-on-rails activerecord entity-attribute-value

在rails上使用ruby,我有一个Customer表,我希望能够添加无限属性(键值对)。我不确定键/值对将是什么,所以我不知道如何做到这一点。例如,一个客户可能是:

  • 客户1物业:
    • 颜色:'黄色'
    • 品牌:'nike'
    • 销售:'33'
  • 客户2属性:
    • color:'red'
    • phone_number:'1111111111'
    • 购买:'2'

基本上,客户可以在键/值对中拥有任意数量的属性。

我该怎么做?

3 个答案:

答案 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_idrelation时的身份。

然后在你的模特中:

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,并将属性哈希值分配给属性属性,并以相同的方式检索它们。