2013-08-21 61 views
5

Active Record Store允許您在單個單元格內序列化參數。基於用戶表單的動態活動記錄存儲訪問器?

I.e.

class User < ActiveRecord::Base 
    store :options, accessors: [ :option1, :option2, :another_random_option ] 
end 

現在,所有訪問器都在users表的「選項」列中被序列化。

u = User.new 
u.option2 = 'some option' 
u.option2 # => 'some option' 

這個偉大的工程我的應用程序,因爲我必須創建一個每天,其中90%的形式是一樣的(用戶名,愛好,興趣等),然後10%的模式有很多形式無(random_option_here,another_random_option_in_another_form)。我也從不需要按無模式選項進行排序。

我所做的是我爲90%的表單字段總是相同創建了1個表,然後我有另一個表與最後10%的字段(我有另一個表的原因是因爲這是belongs_to關係,所以用戶可以在這個表中有很多行)。

<%= form_tag do %> 
    <%= #render partial form for an object that has non-changing fields %> 
    ... 
    <%= #render a schema-less partial form based off an ID passed here %> 
<% end > 

現在唯一的問題是,每次我在自定義窗體創建一個新的領域,我必須給參數添加到活動記錄存儲存取,否則我得到缺少錯誤的方法。如果我可以進入併爲無模式字段創建儘可能多的視圖表單並永遠不更新模型中的訪問器,那將會很好。

所以我的問題是:反正是有所有用戶提交的自定義字段動態添加到陣列的存取,這樣,如果用戶提交的領域「some_random_option1221」,「another_option_here」當時我沒有去成訪問器數組並添加該字段?

謝謝!

回答

11

隨着軌道4和PostgreSQL爲我下面的作品。它看起來像一些小調整軌道3商店的方法也可以使用。

在給定模型實例擁有的存儲散列中的每個字段鍵上動態調用store_accessor。如果您有一個帶有名爲hstore類型選項的列的用戶模型,那麼您已經可以訪問選項散列。 (在軌道3,你會調用存儲方法如在你的問題做出的選擇方法工作的代碼。)

創建做到這一點的方法,只要你的用戶界面增加了一個新的領域。然後,也可以在after_initialize中調用此方法,以便從db加載用戶將在加載時設置字段名訪問器。你可能也想在after_save中調用這個方法。

class User < ActiveRecord::Base 
    after_initialize :add_field_accessors 
    after_save  :add_field_accessors 

    def add_store_accessor field_name 
    singleton_class.class_eval {store_accessor :options, field_name} 
    end 

    def add_field_accessors 
    num_fields = options.try(:keys).try(:count) || 0 
    options.keys.each {|field_name| add_store_accessor field_name} if num_fields > 0 
    end 
end 

然後,每個用戶實例可以根據哪些字段,每個用戶在數據庫中的行爲用戶在選項欄中有不同store_accessor方法。

在您的控制器中,根據用戶添加/刪除/編輯選項的首選用戶界面,可以使用助手方法在用戶上構建選項,並從新建,創建,更新等中調用該選項。

def build_options 
    @user.options = options_hash 
    @user.add_field_accessors 
end 

在Rails 3,而不是調用store_accessor,你會打電話attr_accessor。

請注意,您將無法調用User.new(:option_1 =>'some_option_value'),因爲User類對象沒有訪問器方法(因爲每個用戶實例可能具有不同的屬性。)

+0

好酷,好像是''num_fields = options.try(:keys).try(:count)|| 0''不需要,你可以在選項字段中添加一個默認值''{}'',所以options.keys只是一個空數組。 – zw963