基于用户表单的动态Active Record Store访问器?

时间:2013-08-21 05:41:45

标签: ruby-on-rails ruby ruby-on-rails-4

Active Record Store允许您序列化单个单元格内的参数。

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

现在,所有访问者都在users表的“options”列中序列化。

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 >

现在唯一的问题是每次我在自定义表单中创建一个新字段时,我必须将该参数添加到Active Record Store访问器,否则我会得到一个方法缺失错误。如果我可以进入并为无模式字段创建尽可能多的View表单并且永远不会更新模型中的访问器,那将是很好的。

所以我的问题是:是否有动态添加所有用户提交的自定义字段到访问者数组,这样如果用户提交字段“some_random_option1221”,“another_option_here”然后我不必进入访问者数组并添加该字段?

谢谢!

2 个答案:

答案 0 :(得分:13)

使用rails 4和postgresql以下内容适用于我。通过一些小的调整看起来也可以使用rails 3存储方法。

在给定模型实例拥有的商店哈希中的每个字段键上动态调用store_accessor。如果您的用户模型具有名为hstore类型的选项的列,则您可以访问选项哈希。 (在rails 3中,您可以像问题中的代码一样调用store方法,以使选项方法有效。)

每当用户界面添加新字段时,创建一个方法来执行此操作。然后还调用此方法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方法,具体取决于每个用户在该用户的db行的options列中具有的字段。

在您的控制器中,根据您添加/删除/编辑选项的首选用户界面,您可以使用帮助程序方法在用户上构建选项,并从新建,创建,更新等中调用它。

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

在rails 3中,不是调用store_accessor,而是调用attr_accessor。

请注意,您将无法调用User.new(:option_1 =&gt;'some_option_value'),因为User类对象没有访问器方法(因为每个用户实例可能具有不同的属性。)< / p>

答案 1 :(得分:0)