I use Ruby On Rails together with a PostgreSQL database. For performance reasons I use a jsonb-field with an array of hashes and not extracting this into a specific table. In the real world this blob looks like
[ { "row": 1, "price": 0, "column": 1, "status": 1, "index_row": 1, "contingency": 0, "index_column": 1 }, { "row": 1, "price": 0, "column": 2, "status": 1, "index_row": 1, "contingency": 0, "index_column": 2 }... ]
and works fine.
Now I tried to increase the test coverage and noticed, that I cannot create an array of hashes using the standard fixture approach. Suppose the following:
CREATE TABLE IF NOT EXISTS public.circles
(
id bigint NOT NULL DEFAULT nextval('circles_id_seq'::regclass),
blob jsonb
)
and a fixture file circles.yml with the following content:
templatecircle_1:
blob: <%= [1, 2] %>
This works as expected when running bin/rails test.
templatecircle_1:
blob: {"abc": "def"}
This works as expected, too.
However,
templatecircle_1:
blob: <%= [1, {"abc": "def"}] %>
yields into an ActiveRecord::Fixture::FormatError:
Please note that YAML must be consistently indented using spaces. Tabs are not allowed. Error: (): did not find expected node content while parsing a flow node at line 2 column 11
I even tried to use a workaround as following:
templatecircle_1:
blob: <%= JSON.parse("[1, {\"abc\": \"def\"}]") %>
which gives the same error.
Does anyone has an idea, how I can create an array of hashes in RoR fixtures?
To define "array of hashes" field in the YAML fixtures file, use -
notation for every array element and :
for every hash key/value pair. Don't need ERB syntax or some JSON parsing. Just such structure:
# test/fixtures/circles.yml
templatecircle_1:
blob:
- row: 1
price: 0
column: 1
status: 1
index_row: 1
contingency: 0
index_column: 1
- row: 1
price: 0
column: 2
status: 1
index_row: 1
contingency: 0
index_column: 2
After that you can call inside your test
Circle.first.blob
# => [{
# "row"=>1,
# "price"=>0,
# "column"=>1,
# "status"=>1,
# "index_row"=>1,
# "contingency"=>0,
# "index_column"=>1
# },
# "row"=>1,
# "price"=>0,
# "column"=>2,
# "status"=>1,
# "index_row"=>1,
# "contingency"=>0,
# "index_column"=>2
# }]
As you see it will be parsed automatically
So for [1, {"abc": "def"}]
the structure will be:
# test/fixtures/circles.yml
templatecircle_1:
blob:
- 1
- abc: def
And in Ruby:
Circle.first.blob
# => [1, {"abc"=>"def"}]
It's also possible to use such syntax (just remove ERB from your original attempt):
# test/fixtures/circles.yml
templatecircle_1:
blob: [1, {"abc": "def"}]
And in Ruby:
Circle.first.blob
# => [1, {"abc"=>"def"}]
If you still need ERB by some reasons, you can use to_json
method
# test/fixtures/circles.yml
templatecircle_1:
blob: <%= [1, { "abc": "def" }].to_json %>
And in Ruby:
Circle.first.blob
# => [1, {"abc"=>"def"}]