How to edit a Rails serialized field in a form? How to edit a Rails serialized field in a form? ruby-on-rails ruby-on-rails

How to edit a Rails serialized field in a form?


If you know what the option keys are going to be in advance, you can declare special getters and setters for them like so:

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, :unitsend

The nice thing about this is that it exposes the components of the options array as attributes, which allows you to use the Rails form helpers like so:

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


Well, I had the same problem, and tried not to over-engineer it. The problem is, that although you can pass the serialized hash to fields_for, the fields for function will think, it is an option hash (and not your object), and set the form object to nil. This means, that although you can edit the values, they will not appear after editing. It might be a bug or unexpected behavior of rails and maybe fixed in the future.

However, for now, it is quite easy to get it working (though it took me the whole morning to figure out).

You can leave you model as is and in the view you need to give fields for the object as an open struct. That will properly set the record object (so f2.object will return your options) and secondly it lets the text_field builder access the value from your object/params.

Since I included " || {}", it will work with new/create forms, too.

= 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

Have a great day


emh is almost there. I would think that Rails would return the values to the form fields but it does not. So you can just put it in there manually in the ":value =>" parameter for each field. It doesn't look slick, but it works.

Here it is from top to bottom:

class Widget < ActiveRecord::Base    serialize :options, Hashend<%= 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 %>

Any field you add in the "fields_for" will show up in the serialized hash. You can add or remove fields at will. They will be passed as attributes to the "options" hash and stored as YAML.