【问题标题】:Making virtual attributes be part of one Hash使虚拟属性成为一个哈希的一部分
【发布时间】:2013-03-11 14:38:01
【问题描述】:

我有一个模型,它在数据库中有一个实际列。此列存储为 JSON 配置字符串。我使用了一堆我想在这个配置 JSON 属性中映射的虚拟属性。我基本上不想在数据库中创建一堆列,而是使用这个 JSON 属性来包含所有内容。有没有比下面的defs 更清洁的方法来实现这一点?

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] 之类的东西。有这样的东西吗?

【问题讨论】:

  • 我想出的另一个解决方法是在属性符号数组上使用 class_eval 来生成 getter 和 setter,但这也有点难看。

标签: ruby-on-rails activerecord


【解决方案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

【讨论】:

  • 这很好。但问题是 ActiveRecord::Store 没有将这些声明为attr_accessible,这将导致“ActiveModel::MassAssignmentSecurity::Error: Can't mass-assign protected attributes: background_color, title”。这是意料之中的,因为我可能希望某些属性无法访问。但我想这意味着我需要有一个单独的 attr_accessible 行与相同的数组(或一个 var 与 attr_accessiblestore_accessor 中使用的数组)
【解决方案2】:

Rails 自 3.2 起在 ActiveRecord 中内置了键值存储 - 请参阅此处:

Where can i read more about Rails 3.2's Data Store with key-value in textfield?

在您的情况下,您可以有一个名为 configuration 的文本字段,然后执行以下操作:

类设备

这应该适用于表单等。

【讨论】:

    【解决方案3】:

    想到了两种方法。

    首先,您可以拥有一个属性数组 [: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
    

    【讨论】:

      猜你喜欢
      • 2011-07-22
      • 1970-01-01
      • 1970-01-01
      • 2015-02-08
      • 1970-01-01
      • 2015-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多