Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to customize simple_form for json nested hash

I have some nested data:

@preset = Preset.new
#fields is a postgres json data type
@preset.fields =  {'primary_category' => {'category_id' => 57882}}

I would like to have the same nested structure preserved in the POST params[:preset][:fields] from a form submit so I have this in my form partial:

<%= text_field_tag("preset[fields][primary_category][category_id]",nil) -%>

Simple form does not know how to deal with postgres new types like hstore or json types. In my case I don't really need it for validation or to detect the data type. Is there a way I can extend SimpleForm to skip detection of the column types and just output the same existing bootstrap boilerplate that it outputs for textfields, but for my arbitrary json nested keys?

Maybe a usage like this:

<%= f.input 'preset[fields][primary_category][category_id]', :as => :json_text_field %>

To output the same thing as helper above, but surrounded with the label, and control-group classed divs, etc.

I have looked into extending the input base class per the documentation.

class JsonTextFieldInput < SimpleForm::Inputs::Base
  def input
    "#{@builder.text_field(???, input_html_options)}".html_safe
  end
end

But here is where I get lost as I'm not sure what to pass to the @builder to bypass checking of attribute name with my own logic to map it hash keys. Also that only changes the form input and not the label, which needs some modification as well. In either case I wasn't able to get very far and I could use some guidance.

like image 669
Homan Avatar asked Aug 10 '13 15:08

Homan


1 Answers

I'm using this for jsonb / json input:

class JsonbInput < SimpleForm::Inputs::StringInput
  def input()
    out = ActiveSupport::SafeBuffer.new
    Hash[object.send(attribute_name).sort].each do | k, v|
      out << template.content_tag(:div, class: 'group') do
        template.concat @builder.label(k, object.send(attribute_name), label_html_options)
        template.concat @builder.text_field(k, input_html_options)
      end
    end
    out
  end

  def input_html_options
    {class: 'string form-control'}
  end

end

You also need to use store_accessor in your model.

like image 125
adrian Avatar answered Oct 02 '22 21:10

adrian