2016-09-23 37 views
1

在我的軌道模型中,我有一個存儲一些元信息的JSON列。 這是要從用戶輸入的形式。正確的方式來定義模型上的虛擬屬性在軌道中JSON列中的鍵

由於JSON列的鍵不是模型的屬性,我不能直接在form_for中使用它們,而是需要定義一個虛擬屬性。

由於這個虛擬屬性的數量可能變得任意長,我想使用元編程來定義屬性。

但我在this question上試過了答案,但是當我在模型中使用常量時出現一個錯誤,說明該常量是未定義的。所以我直接在數組中添加了鍵的符號,並在模塊中迭代它們。當我這樣做時,我得到一個錯誤,說堆棧層次太深。

請有人可以幫我一下嗎?

回答

2

如果您使用PostgreSQL特定列(如hstorejson),則只需使用store_accessor來生成訪問器方法。 請注意,這些列使用字符串鍵控哈希,並且不允許使用符號進行訪問。

class Model < ActiveRecord::Base 
    store_accessor :my_json_column, [ :key_1, :key_2, key_3 ] 
end 

它在底下做了什麼?它有明確的寫\讀輔助方法:

def store_accessor(store_attribute, *keys) 
    keys = keys.flatten 

    _store_accessors_module.module_eval do 
    keys.each do |key| 
     define_method("#{key}=") do |value| 
     write_store_attribute(store_attribute, key, value) 
     end 

     define_method(key) do 
     read_store_attribute(store_attribute, key) 
     end 
    end 
    end 

#.....

store

+0

謝謝您的答覆。我不知道這件事。如果你不介意,那麼請你能告訴我哪個方法應該是首選的('store_accessor'或在迭代器中使用'define_method'),爲什麼? –

+1

你應該使用Rails和Rails核心庫提供的方法和宏來避免核心lib方法的重複,Rails代碼庫有很好的測試覆蓋率。但是你的答案也適合於教育目的。 + 1 –

+2

_好的編碼器可以編寫新的代碼,忍者編碼器可以使舊的代碼再次工作._ –

2

我想通了。我返回屬性作爲JSON列的關鍵字,現在它工作正常。

# lib/virtuals.rb 
module Virtuals 

    %W(key_1 key_2 key_3).each do |attr| 
    define_method(attr) do 
     self.my_json_column[attr] 
    end 

    define_method("#{attr}=") do |val| 
     self.my_json_column[attr] = val 
    end 
    end 
end 

在我的模型,我只是需要包括上述模塊,並將其在form_for和更新工作正常,正確的爲好。

相關問題