2013-03-21 55 views
0

我有一个模型在数据库中有一个实际列。该列存储为配置的JSON字符串。我使用了一堆虚拟属性,我想在这个配置JSON属性中映射这些属性。我基本上不想在数据库中创建一堆列,而是使用这一个JSON属性来包含所有内容。有没有比实现这个的def更简洁的方法?使虚拟属性成为一个哈希的一部分

class Device < ActiveRecord::Base 
    attr_accessible :configuration 
    serialize :configuration, JSON 

    attr_accessor :background_color, :title 

    # below is ew 
    def background_color; self.configuration["background_color"]; end 
    def background_color=(value); self.configuration["background_color"] = value; end 

    def title; self.configuration["title"]; end 
    def title=(value); self.configuration["title"] = value; end 
end 

理想情况下,我会寻找像attr_maps_to_hash :configuration, [:background_color, :title]。有这样的事情存在吗?

+0

我想到的另一个解决方法是在属性符号数组上使用'class_eval'来生成getters和setters,但这也很丑陋。 – Larry 2013-03-21 21:43:36

回答

1

您可以使用ActiveRecord::Store这个。

class User < ActiveRecord::Base 
    store :settings, accessors: [ :color, :homepage ] 
end 

u = User.new(color: 'black', homepage: '37signals.com') 
u.color       # Accessor stored attribute 
u.settings[:country] = 'Denmark' # Any attribute, even if not specified with an accessor 

# Add additional accessors to an existing store through store_accessor 
class SuperUser < User 
    store_accessor :settings, :privileges, :servants 
end 

如果您使用的是PostgreSQL,请查看HStore

+0

这很好。问题是,ActiveRecord :: Store没有将这些声明声明为'attr_accessible',这将导致“ActiveModel :: MassAssignmentSecurity :: Error:无法批量分配受保护的属性:background_color,title”。这是预料之中的,因为我可能想要一些属性无法访问。但我想这意味着我需要有一个单独的'attr_accessible'行具有相​​同的数组(或者在'attr_accessible'和'store_accessor'中使用了一个var) – Larry 2013-03-21 22:25:22

0

想到两种方法。首先,你可以有一个你的属性[:background_color,:title]数组,然后在调用define_method的时候迭代它们。您将定义两个方法,define(method_name)和define(“#{method_name} =”)。

其次,类似的想法,但使用方法丢失。

def method_missing(method_name, *args, &block) 
    ...see if it's a get or set... 
    ...do your stuff... 
    ...rain dance... 
    ...yay... 
end