Reputation: 20076
I have a serialized Array field in my model called :cords
, and part of my form looks like so:
<%= form_for @group do |f| %>
....
<p>
<%= f.label :cords %><br>
<%= f.text_field :cords, name: "group[cords][]" %>
</p>
....
Then inside my controller, I attempt to use it like so
@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 though, because when I type in some array like [[1,2],[3,4]]
I see the SQL insert is
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 is cords
submitted as ["cords", "---\n- \"[[1,2],[3,4],[5.5,6]]\"\n"]
? I believe I'm doing something wrong with my actual form setup
Upvotes: 3
Views: 1633
Reputation: 418
Rails serialized column indeed allow us to store complex data types such as array, but they do so in YAML format by default.
What you do is pass a text as group[cords][]
param.
So, what you should get in your params
is {group: {cords: [ "[[1,2],[3,4],[5.5,6]]" ]}}
. Take notice, that cords
is array of one element, which is string you pass to it: "[[1,2],[3,4],[5.5,6]]"
That array gets serialized in compliance with YAML scalar syntax: "---\n- \"[[1,2],[3,4],[5.5,6]]\"\n"
. Let's look at it up close, first substituting newlines:
---
- "[[1,2],[3,4],[5.5,6]]"
#here also newline
Three hyphens indicate start of YAML document.
Array is packed like this:
- "first_element"
- "second_element"
- "third_element"
Is equal to ["first_element", "second_element", "third_element"]
Backslash before quotation marks just escape those in SQL denoting that quotes are part of the string.
So, as you can see, rails do just what it is supposed / you told it to do: it gets single string as one element of array and it stores one element of array, containing that string.
What you should do if you still want to get user input as array is transform that manually.
[]
in text_field
: f.text_field :cords, name:
"group[cords]"
def cords_to_a
# get the params[:group][:cords], if it's 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)
Take notice: you still will get a "strange" string in your INSERT
statement, because that will contain YAML-encoded array: essentially, a string.
Upvotes: 6