基于用户表单的动态 Active Record Store 访问器? [英] Dynamic Active Record Store accessors based off a user form?

查看:40
本文介绍了基于用户表单的动态 Active Record Store 访问器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

class User 

现在所有访问器都在用户表的选项"列中进行了序列化.

u = User.newu.option2 = '一些选项'u.option2 # =>'一些选择'

这对我的应用程序非常有用,因为我每天必须创建许多表单,其中 90% 的表单是相同的(用户名、爱好、兴趣等),然后 10% 是无模式的(random_option_here,another_random_option_in_another_form).我也永远不需要按无模式选项排序.

我所做的是为始终相同的 90% 的表单字段创建了 1 个表,然后我有另一个包含最后 10% 字段的表(我有另一个表的原因是因为这是一个belongs_to 关系,所以用户可以在这个表中有很多行).

<%= form_tag do %><%= #render 具有不变字段的对象的部分形式 %>...<%= #render a schema-less partial form based on an ID 通过这里 %><%结束>

现在唯一的问题是,每次在自定义表单中创建新字段时,我都必须将该参数添加到 Active Record Store 访问器中,否则会出现方法缺失错误.如果我可以为无模式字段创建任意数量的视图表单并且永远不更新模型中的访问器,那就太好了.

所以我的问题是:无论如何,是否可以将所有用户提交的自定义字段动态添加到访问器数组中,这样如果用户提交了字段some_random_option1221"、another_option_here",那么我就不必进入访问器数组并添加该字段?

谢谢!

解决方案

对于 rails 4 和 postgresql,以下对我有用.看起来只要稍微调整一下 rails 3 store 方法就可以使用了.

在给定模型实例拥有的存储哈希中的每个字段键上动态调用 store_accessor.如果您有一个 User 模型,其列名为 options 类型为 hstore,则您已经可以访问 options 哈希.(在 rails 3 中,您将像问题中的代码一样调用 store 方法以使 options 方法起作用.)

创建一个方法来在您的用户界面添加新字段时执行此操作.然后也调用此方法 after_initialize 以便从数据库加载用户将在加载时设置字段名称访问器.您可能还想在 after_save 中调用此方法.

class User 0结尾结尾

然后每个用户实例可以有不同的 store_accessor 方法,具体取决于每个用户在该用户的 db 行的选项列中具有哪些字段.

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

def build_options@user.options = options_hash@user.add_field_accessors结尾

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

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

Active Record Store allows you to serialize parameters inside a single cell.

I.e.

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

All the accessors are serialized inside the "options" column of the users table now.

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

This works great for my application because I have to create many forms on a daily basis, where 90% of the form is the same (username, hobbies, interests, etc.) and then 10% are schema-less (random_option_here, another_random_option_in_another_form). I also never need to sort by the schema-less options.

What I did was I created 1 table for the 90% of the form fields that are always the same, and then I have another table with the last 10% of the fields (the reason I have another table is because this is a belongs_to relationship, so the user can have many rows in this table).

<%= 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 >

Now the only problem is that every time I create a new field in the custom form, I have to add that parameter to the Active Record Store accessors, otherwise I get a method missing error. It would be nice if I could just go in and create as many View forms as I want for the schema-less fields and never update the accessors in the Model.

So my question is: Is there anyway to dynamically add all the user submitted custom fields to the accessors array, that way if the user submitted fields "some_random_option1221", "another_option_here" then I don't have to go into the accessors array and add that field?

Thanks!

解决方案

With rails 4 and postgresql the following works for me. It looks like with some minor tweaking the rails 3 store methods could also be used.

Call store_accessor dynamically on each of the field keys in the store hash owned by a given model instance. If you have a User model with a column named options of type hstore, then you can already access the options hash. (In rails 3, you would call the store method as in the code in your question to make the options method work.)

Create a method to do this whenever your user interface adds a new field. Then also call this method after_initialize so loading a user from the db will set up the field name accessors at load time. You might also want to call this method 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

Then each user instance can have different store_accessor methods depending on what fields each user has in the options column in the db row for that user.

In your controller, depending on your preferred user interface for adding/removing/editing the options, you can have a helper method to build the options on a user, and call it from new, create, update, etc.

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

In rails 3, rather than calling store_accessor, you would be calling attr_accessor.

Note that you won't be able to call User.new(:option_1=>'some_option_value') because the User class object doesn't have the accessor methods (since each user instance could have different attributes.)

这篇关于基于用户表单的动态 Active Record Store 访问器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆