2014-04-15 29 views
7

在rails上使用ruby,我有一個Customer表,我希望能夠添加無限的屬性(鍵值對)。我不確定鍵/值對會是什麼,所以我不知道如何做到這一點。例如,一個客戶可能是:ActiveRecord模型的無限任意屬性(鍵/值對)

  • 客戶1個屬性:
    • 顏色: '黃'
    • 品牌: '耐克'
    • 銷售: '33'
  • 客戶2性能:
    • 顏色:'紅'
    • phone_numb ER: '1111111111'
    • 購買: '2'

基本上,客戶可以具有任何數量的鍵/值對的特性。

我該怎麼做?

回答

1

您應該可以使用serialize來實現此目的,並將屬性散列分配給您的屬性屬性,並以相同的方式檢索它們。

+0

然而,這將使得通過這些屬性查詢(即使不是不可能)也很困難。 –

+0

這取決於使用的數據庫。 Postgres很容易支持 - http://travisjeffery.com/b/2012/02/using-postgress-hstore-with-rails/ –

+0

是的,如果你安裝了寶石。 –

10

執行此操作的「傳統」方法是使用實​​體屬性值或EAV模式。顧名思義,您將創建一個包含三列的新表:一個用於「實體」,在本例中爲Customer,一個用於「屬性」名稱或鍵,另一個用於值。所以,你有一個像這樣的表:

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和索引當然也許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)。如果你走這條路線,你可能想要在Customer上定義一些便利的方法來使訪問和更新屬性變得不那麼麻煩。我猜測有可能是專門用於使EAV模式與ActiveRecord一起工作的寶石,但我不知道它們是否在我頭頂,我希望你能原諒我不使用谷歌搜索,因爲我是移動設備。

布拉德·韋斯指出,如果你只需要存儲的任意屬性,而不是由他們查詢,serialize是一個偉大的選擇,如果你使用PostgreSQL連查詢的問題是可以克服由於其巨大的hstore功能。

祝你好運!

+0

正確的,你救了我的麻煩 - 說得好! –

+0

哇,很好的回答(你也是,布拉德)。我使用序列化,但這也非常有趣。非常感謝 –

+1

有誰知道在多個Rails模型中使用這種模式的任何標準Rails gems? –

1

您可能想要查看hydra_attribute gem,它是ActiveRecord模型的實體 - 屬性 - 值(EAV)模式的實現。