Rails 5 form to submit array passed as string

I have a serialized Array field in my model called :cords

and part of my form looks like this:

<%= form_for @group do |f| %>
    ....
    <p>
        <%= f.label :cords %><br>
        <%= f.text_field :cords, name: "group[cords][]" %>
    </p>
    ....

      

Then, inside my controller, I try to use it like this

    @group = Group.new(params.require(:group).permit(:name, :members, cords: [] ))

    if @group.save
        redirect_to @group
    else
        render 'new'
    end

      

This doesn't seem to work because when I enter some array like [[1,2],[3,4]]

I see that the SQL insert

INSERT INTO "groups" ("cords", "name", "members", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?)  [["cords", "---\n- \"[[1,2],[3,4],[5.5,6]]\"\n"], ["name", "GG"], ["members", 55], ["created_at", "2017-06-12 02:13:37.462355"], ["updated_at", "2017-06-12 02:13:37.462355"]]

      

Why cords

is it presented as ["cords", "---\n- \"[[1,2],[3,4],[5.5,6]]\"\n"]

? I believe I am doing something wrong with my actual form setup

+3


source to share


1 answer


Explanation of the problem:

Rails' segmented column does allow storing complex data types like array, but they do it in YAML format by default. What you do is pass the text as group[cords][]

param. So, what you should get into params

is this {group: {cords: [ "[[1,2],[3,4],[5.5,6]]" ]}}

. Note , that cords

is an array of one element, which is the string you pass to it
:"[[1,2],[3,4],[5.5,6]]"

This array is serialized according to the scalar syntax, the YAML: "---\n- \"[[1,2],[3,4],[5.5,6]]\"\n"

. Let's take a closer look at this, first replacing newlines:

---
- "[[1,2],[3,4],[5.5,6]]"
#here also newline

      

Three hyphens indicate the beginning of a YAML document.

The array is packed like this:

- "first_element"
- "second_element"
- "third_element"

      

Is equal ["first_element", "second_element", "third_element"]

The backslash before quotation marks simply removes those from SQL that indicate that quotation marks are part of the string.



So, as you can see, rails does exactly what it is supposed to do / you told it to: it gets one string as one array element and stores one array element containing that string.

Decision:

What to do if you still want user input as the array will convert it manually.

  • Cast []

    in text_field

    :f.text_field :cords, name: "group[cords]"

  • In your controller, convert this text to a ruby ​​array, for example:
def cords_to_a
  # get the params[:group][:cords], if it empty use empty array string
  cords = params.dig(:group, :cords).presence || "[]"
  # parse it, possibly you also want to handle parse exceptions
  # and transform parsed array as something else
  # also, user will be able to save any json object
  # to your serialized field, and it will be parsed
  # accordingly: either to array or to hash
  JSON.parse cords
end

def group_params
  params.require(:group).permit(:name, :members).merge({cords: cords_to_a})
end

      

and after that use Group.new(group_params)

Note that you will still end up with a "strange" string in the statement INSERT

because it will contain a YAML encoded array: essentially a string.

Further reading:

+5


source







All Articles