如何编辑一个窗体中的Rails序列化字段?

我有一个数据模型在我的Rails项目有一个序列化字段:

class Widget < ActiveRecord::Base serialize :options end 

选项字段可以有可变的数据信息。 例如,以下是Fixtures文件中一条logging的选项字段:

  options: query_id: 2 axis_y: 'percent' axis_x: 'text' units: '%' css_class: 'occupancy' dom_hook: '#average-occupancy-by-day' table_scale: 1 

我的问题是让用户在标准表单视图中编辑此信息的正确方法是什么?

如果你只是使用一个简单的文本区域字段的选项字段,你只会得到一个yaml转储表示,该数据将被发回作为一个string。

在Rails中编辑一个序列化的散列字段的最佳方式是什么?

如果你事先知道选项键是什么,你可以像这样为它们声明特殊的getter和setter:

 class Widget < ActiveRecord::Base serialize :options def self.serialized_attr_accessor(*args) args.each do |method_name| eval " def #{method_name} (self.options || {})[:#{method_name}] end def #{method_name}=(value) self.options ||= {} self.options[:#{method_name}] = value end attr_accessible :#{method_name} " end end serialized_attr_accessor :query_id, :axis_y, :axis_x, :units end 

关于这一点的好处是,它将选项数组的组件暴露为属性,这使您可以像这样使用Rails窗体助手:

 #haml - form_for @widget do |f| = f.text_field :axis_y = f.text_field :axis_x = f.text_field :unit 

那么,我有同样的问题,并试图不要过度devise它。 问题是,尽pipe你可以将序列化的散列传递给fields_for,函数的字段会认为它是一个选项散列(而不是你的对象),并将表单对象设置为nil。 这意味着,虽然您可以编辑这些值,但编辑后不会显示。 这可能是一个错误或意外的轨道行为,并可能在未来修复。

但是,现在呢,这个工作起来很容易(尽pipe我花了整整一个早上才弄清楚)。

你可以让你的模型保持原样,并且在视图中你需要给这个对象赋予一个开放的结构体。 这将正确设置logging对象(所以f2.object将返回您的选项),其次它让text_field构build器访问您的对象/参数值。

因为我包含了“|| {}”,所以也可以使用新build/创build表单。

 = form_for @widget do |f| = f.fields_for :options, OpenStruct.new(f.object.options || {}) do |f2| = f2.text_field :axis_y = f2.text_field :axis_x = f2.text_field :unit 

祝你有美好的一天

他们几乎在那里。 我会认为,Rails会将值返回到表单字段,但它不会。 所以你可以在每个字段的“:value =>”参数中手动input。 它看起来不光滑,但它的工作原理。

这里是从上到下:

 class Widget < ActiveRecord::Base serialize :options, Hash end <%= form_for :widget, @widget, :url => {:action => "update"}, :html => {:method => :put} do |f| %> <%= f.error_messages %> <%= f.fields_for :options do |o| %> <%= o.text_field :axis_x, :size => 10, :value => @widget.options["axis_x"] %> <%= o.text_field :axis_y, :size => 10, :value => @widget.options["axis_y"] %> <% end %> <% end %> 

您在“fields_for”中添加的任何字段都将显示在序列化哈希中。 您可以随意添加或删除字段。 它们将作为属性传递给“选项”散列并存储为YAML。

不需要setter / getters,我只是在模型中定义:

 serialize :content_hash, Hash 

然后在视图中,我做(与simple_form,但类似的香草Rails):

  = f.simple_fields_for :content_hash do |chf| - @model_instance.content_hash.each_pair do |k,v| =chf.input k.to_sym, :as => :string, :input_html => {:value => v} 

我最后一个问题是如何让用户添加一个新的键/值对。

我一直在努力解决一个非常类似的问题。 我在这里find的解决scheme对我非常有帮助。 谢谢@austinfromboston,@ Christian-Butske,@sbzoom和其他人。 不过,我认为这些答案可能略有过时。 以下是Rails 5和Ruby 2.3的工作原理:

forms如下:

 <%= f.label :options %> <%= f.fields_for :options do |o| %> <%= o.label :axis_y %> <%= o.text_field :axis_y %> <%= o.label :axis_x %> <%= o.text_field :axis_x %> ... <% end %> 

然后在控制器中,我必须更新强参数,如下所示:

 def widget_params params.require(:widget).permit(:any, :regular, :parameters, :options => [:axis_y, :axis_x, ...]) end 

序列化的哈希参数出现在参数列表的末尾似乎很重要。 否则,Rails会期望下一个参数也是一个序列化的散列。

在视图中,我使用了一些简单的if / then逻辑,只显示散列,如果它不是空的,然后只显示键/值对的值不为零。

我试图做类似的事情,我发现了这样的作品:

 <%= form_for @search do |f| %> <%= f.fields_for :params, @search.params do |p| %> <%= p.select "property_id", [[ "All", 0 ]] + PropertyType.all.collect { |pt| [ pt.value, pt.id ] } %> <%= p.text_field :min_square_footage, :size => 10, :placeholder => "Min" %> <%= p.text_field :max_square_footage, :size => 10, :placeholder => "Max" %> <% end %> <% end %> 

除了表单字段在表单呈现时不填充。 当表单提交的价值来通过蛮好的,我可以这样做:

 @search = Search.new(params[:search]) 

所以它的“一半”工作…

我会build议一些简单的,因为所有的时间,当用户将保存表单,你会得到string。 所以你可以使用例如之前筛选和parsing这些数据:

 before_save do widget.options = YAML.parse(widget.options).to_ruby end 

当然你应该添加validation,如果这是正确的YAML。 但它应该工作。