How to edit a Rails serialized field in a form?

后端 未结 8 641
-上瘾入骨i
-上瘾入骨i 2020-12-04 07:16

I have a data model in my Rails project that has a serialized field:

class Widget < ActiveRecord::Base
  serialize :options
end

The opti

相关标签:
8条回答
  • 2020-12-04 07:46

    I will suggest something simple, because all the time, when user will save form You will get string. So You can use for example before filter and parse those data like that:

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

    of course You should add validation if this is correct YAML. But it should works.

    0 讨论(0)
  • 2020-12-04 07:47

    I'm trying to do something similar and I found this sort of works:

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

    except that the form fields aren't populated when the form is rendered. when the form is submitted the values come through just fine and i can do:

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

    so its "half" working...

    0 讨论(0)
  • 2020-12-04 07:52

    I've been struggling with a very similar problem. The solutions I found here were very helpful to me. Thank you @austinfromboston, @Christian-Butske, @sbzoom, and everyone else. However, I think these answers might be slightly out-of-date. Here's what worked for me with Rails 5 and ruby 2.3:

    In the form:

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

    and then in the controller I had to update the strong parameters like so:

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

    It seems to be important that the serialized hash parameter comes at the end of the list of parameters. Otherwise, Rails will expect the next parameter to also be a serialized hash.

    In the view I used some simple if/then logic to only display the hash if it is not empty and then to only display key/value pairs where the value was not nil.

    0 讨论(0)
  • 2020-12-04 08:03

    No need setter/getters, I just defined in the model:

    serialize :content_hash, Hash
    

    Then in the view, I do (with simple_form, but similar with vanilla 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}
    

    My last issue is how to let the user add a new key/value pair.

    0 讨论(0)
  • 2020-12-04 08:05

    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, :units
    end
    

    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
    
    0 讨论(0)
  • 2020-12-04 08:07

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

    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.

    0 讨论(0)
提交回复
热议问题