2014-09-25 119 views
7

我有一個SaaS應用程序,帳戶想要在用戶模型上保存不同類型的信息。例如,一個帳戶可能希望保存年齡和生日,但在另一個帳戶中,他們不會使用這些列,並且希望保存關於頭髮顏色和身高的信息。Rails:模型上的動態列/屬性?

這些僅僅是一些例子,但我如何構建我的模型和數據庫,以便它可以很好地適用於「定製的,動態的」列而不會創建太多的空屬性。

+0

jc,你最終會在哪裏用這個? – mmcrae 2015-03-04 14:52:40

+1

@mmcrae我結束了使用postgresql的.json數據結構,並將任何自定義列轉儲到此.json數據字段中。 – kibaekr 2015-03-05 09:37:43

回答

5

對我來說,這個聲音就像一個完美的例子,你想使用一個無模式的NoSQL數據庫。或者(如果你想堅持SQL),你可以有一個基地User模型與has_many :attributes協會。其中一個屬性只是key('年齡','生日','頭髮顏色')和一個值的組合。複雜性來自不同的數據類型和同時涉及多個屬性的查詢。

0

你的模式可能是這樣的:

create_table "accounts", :force => true do |t| 
    t.integer "user_id" 
    t.string "data_key" 
    t.string "data_value" 
end 

Account模型

belongs_to :user  
DATA_KEYS = ['age', 'birthdate', 'hair_color', 'height' ] # etc.. 

用戶模型

has_many :accounts 
Account::DATA_KEYS.each do |method| 
    # getter method 
    define_method(method) do 
    accounts.find_by_data_key(method).try(:data_value) 
    end 

    # setter method 
    define_method("#{method}=") do |value| 
    data = accounts.find_or_initialize_by_data_key(method) 
    data.data_value = value.strip 
    data.save 
    end 
end 

您可以獲取和設置帳戶數據值

例如user.age =>將返回的用戶年齡

user.hair_color = 'brown' =>將設置頭髮的顏色

+0

如果用戶屬於多個帳戶,此代碼是否會更改?並且帳戶會選擇他們是否想要支持某個data_key,並且該帳戶中的用戶將擁有這些data_keys上的data_values – kibaekr 2014-09-26 00:29:42

+0

我收到此錯誤:「NoMethodError:undefined method find_by_data_key for#」 – kibaekr 2014-09-26 04:30:33

+0

@ kibaekr,用戶模型具有'has_many:accounts'並且'find_by_data_key'方法不是針對'User'對象,而是針對'Account'模型。 – shweta 2014-09-26 05:08:56

0

我建議去一個的NoSQL數據庫。它們是專門爲這種情況設計的,所以你不必爲了工作而做瘋狂的事情。 MongoDB結合MongoID是一個非常穩固的解決方案。

唯一的缺點可能是託管,因爲它往往是輕微的,至少,更昂貴。

7

以下是兩個選項。 1. NoSQL數據庫。 2. Rails 4 Store功能。

+1

Rails Store看起來非常有趣,適用於許多您希望堅持使用常用數據庫和模型的情況,以及「當您不關心能夠在單個記錄的上下文之外查詢該商店時」 - 引用文檔。適合我。 – DannyB 2015-12-16 12:21:12

1

如果你使用PostgreSQL,你可以看看hstore那麼你可以保存信息序列化,實際上你可以對這些哈希一些疑問BTW軌道4,5已經包括此功能,但如果您使用的是舊版本的Rails你可以包含這個寶石。 https://github.com/diogob/activerecord-postgres-hstore在你的Gemfile中,你應該可以像下面這樣開始播放:

user = User.new 
user.preferences = { 
    email: "[email protected]", 
    github: "heridev" 
} 

user.save! 
user.reload 

# Searching 
User.where("preferences @> hstore(:key, :value)", key: "email", value: "[email protected]").first