使用带有序列化自定义类的Rails表单助手

我正在尝试在单个DB字段中保存选项的哈希值。 表单能够将数据保存到数据库,但是当我去编辑它时无法再次检索它(例如,除了wp_options字段之外,所有其他字段都是预先填充的)。

class Profile < ActiveRecord::Base serialize :wp_options end 

这是我的自定义类:

 class WP_Options attr_accessor :wp_name, :wp_desc, :wp_limit end 

在我的forms:

  true) do |f| %> ...    ... 

在我的控制器中:

 @profile = Profile.new(:wp_options => WP_Options.new) 

在我的数据库列’wp_options’中:

 --- !map:ActiveSupport::HashWithIndifferentAccess wp_name: Test 

任何建议都会非常感激。

实际上这很容易。 您需要使用带reader方法的类。 您可以使用不同的方式创建它,但最简单的方法是使用OpenStruct类(注意,它将无法查看OpenStruct实例方法中的字段…此类无法重新定义方法)。

在您的表单中,您应该添加:

 <%= f.fields_for :wp_options, @profile.wp_options do |wp_options| %> 

而不是@profile(如果你有动态变量),你可以使用f.object.wp_options

对于模型Profile您应该添加wp_options方法。

 def wp_options OpenStruct.new(self.attributes['wp_options']) end 

在这种情况下,它只有在序列化的wp_options是Hash类时才有效。

希望有所帮助。

PS。 我使用相同的技术,但因为我有type哈希键,OpenStruct无法创建它,所以我使用简单的Struct类。 我有data列:

 def data keys = current_data.keys data = attributes[:data] Struct.new(*keys).new(*keys.map { |k| data[k] }) end 

有点不那么琐碎,但无论如何都是相同的方法(在此之前我创建了特殊的类,但现在我知道Struct是创建这类东西的更好方法。你可以在这里找到更多的想法: 我如何使用哈希键作为一个类的方法? )

对于那些使用Dmitry的解决方案,在rails 3.0.5上(不确定上一个/下一个版本,所以尝试之前),添加

 require 'ostruct' 

到您的environment.rb文件,以包含OpenStruct。

如果您要使用JSON进行序列化,请在您的模型中添加(哦,我对RoR很新,所以请随时仔细检查并建议一个更好的“工作”解决方案然后这个)( 我的变量名称更改为匹配上面的例子 ):

 before_save :json_serialize after_save :json_deserialize after_find :json_deserialize def json_serialize self.wp_options = ActiveSupport::JSON.encode(self.attributes['wp_options']) end def json_deserialize unless (self.attributes['wp_options'].nil?) self.wp_options = ActiveSupport::JSON.decode(self.attributes['wp_options'].to_s) end end 

最后一点:老实说,我不确定为什么必须存储到self.wp_options而不是self.attributes [‘wp_options’],如果有人能解释它会很酷。

我遇到了同样的问题。 我的解决方案如下:

  1. 在助手中定义方法:

     def wp_options_text_field(profile, wp_options, name) wp_options.text_field name, :value => profile.wp_options[name] end 
  2. 在你看来:

     <%= form_for(@profile, :remote => true) do |f| %> ... <%= f.fields_for :wp_options do |wp_options| %> <%= wp_options_text_field :wp_name %> <% end %> ... 

这里唯一的问题是你需要为你将使用的每个辅助方法定义方法。 在我的情况下,我只使用了2种方法,并没有痛苦。