Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

json field in edit form with rails

I have a project with ruby 2.5 and rails 5.2. It has a model called Fruit, which includes two fields: name:string and options:json. I want to use options to store some data like color, size, etc.

Now I have a form:

<%= form_with(model: fruit, local: true) do |form| %>

  <div class="field">
    <%= form.label :name %>
    <%= form.text_field :name %>
  </div>

  <div class="field">
    <%= form.label :options %>

    <%= form.fields :options do |field| %>
      <%= field.text_field :color %>
      <%= field.text_field :size %>
    <% end %>
  </div>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

It will successfully save the data to database, including the color and size in options. However, it cannot display the existing data in options when I edit it.

It means when I edit the fruit, if I don't set the color and size again, the existing data will lost.

Does anyone know how to make it work properly?


The problem marked as duplicate is different. In that problem, they are asking if a json object can transfer to string or not.

My question is to display the value in the form by key.

like image 608
Stephen Avatar asked Jun 14 '18 01:06

Stephen


1 Answers

I have found the solution.

The form will show each value by sending a getter method to object. The object is stored in the form builder as form.object, and represent the model.

However, when created a sub-form by fields, the object is not included. It needs to be passed in:

<%= form.fields :options, model: form.object.options do |field| %>

In this way, the field.object will be assigned to options as Hash format.

However, it's not enough. The form tries to get the value by calling the method. But the hash attributes cannot accept method call. options.color won't return the value so the value isn't shown on the form yet.

One solution is transferring the model to OpenStruct. OpenStruct allows you to call the key as a method to get the value. So my solution to make the form works is:

<%= form.fields :options, model: OpenStruct.new(form.object.options) do |field| %>
like image 164
Stephen Avatar answered Oct 18 '22 15:10

Stephen