Is there a way to seed hashes using the Faker gem? - ruby-on-rails

I am trying to seed some data but I have a field that takes in a hash. When I do the following
50.times do
Event.create(
name: Faker::Internet.name,
data: Faker::Lorem.words(4),
uri: Faker::Internet.url
)
end
events = Event.all
I get an error saying that data is being seeded as an array since it's a hash field. Is there a work around this?
rake aborted!
Mongoid::Errors::InvalidValue:
Problem:
Value of type Array cannot be written to a field of type Hash
Summary:
Tried to set a value of type Array to a field of type Hash
I tried doing the following:
data: Faker::Lorem.words(4).to_h
but it doesn't seem to work.

You could do
Event.create(
name: Faker::Internet.name,
data: Hash[*Faker::Lorem.words(4)],
uri: Faker::Internet.url
)

Use Faker::Crypto.sha256.
Example:
> Faker::Crypto.sha256
=> "ee25a4b399dd3c748d310aedd458f0662d4736f470d2c8342553e1e8998b4bc2"

Related

Rails update_attributes with dynamic hash

I have a rails app in which I am trying to update a model with the attributes I am getting in the hash.
My code is:
attr_hash = {"name"=>"cat_name"}
#category.update_attributes(attr_hash, :type => 'sample')
Here is what I want that type will be fixed and the attr hash can be any attribute base on the form submit. But this gives me an error. Any ideas?
attr_hash = {"name"=>"cat_name"}
#category.update_attributes(attr_hash.merge(type: "sample"))
(because update_attributes takes only one hash)
Explanation:
Currently you're passing this:
update_attributes({"name"=>"cat_name"}, {type: "sample"})
but you want this:
update_attributes({"name"=>"cat_name", type: "sample"})
So you need to merge these two hashes.

How can I put a Postgres JSON value into a Rails fixture?

I just added a Postgres json type to a Rails/Active Record table I'm working with.
I'd like to populate a record with a default value in Rails fixtures:
fixture_id:
existing_column: "foobar"
newly_added_column: <%= JSON.dump({:reason => 'foobar'}) %>
Previously, I'd stored stringified JSON this way in a text column. However, when I now run this unit test:
test "my test" do
sut = fixtures(:fixture_id)
assert_not_nil sut.newly_added_column
end
The test fails. Because it is JSON at the database level, I don't think it's useful to dump it to a string, but the YAML fixtures can't seem to keep an object as a Hash (when I try it without the JSON.dump, I get ActiveRecord::Fixture::FormatError: a YAML error occurred parsing).
Mind you, I am using Rails 3, so I think some of the support for this may be in Rails 4, but in Rails 3, the migration to add a json Postgres column type still work.
I believe your fixture can be as simple as:
fixture_id:
existing_column: foobar
newly_added_column: {'reason':'foobar'}
To avoid having lengthy JSON structure inline in your fixtures, YAML provide a useful > operator
fixture_id:
existing_column: "foobar"
data: >
{
"can_edit": true,
"can_se": true,
"can_share": true,
"something_else": true
}
In Rails 5 it is possible to simply describe the JSON in YAML format. It will then be converted into correct JSON when fixtures are loaded in the DB:
parent:
name: A fixture
json_field:
- name: JSON Object 1
foo: bar
- name: JSON Object 2
foo: baz
(tested with JSONB attributes in Postgres)
If you are using ActiveRecord to generate content for your fixtures, you have to ensure that it converts attribute values to json. If you rely on the default serialization, it will produce hash rocket text which is invalid YAML.
For example, I have a legacy database that I am using to create fixtures for my new application (relevant code listed below):
presenter.rb
module FixturePresenter
def replacer(str)
str.downcase.tr(' ', '_').tr('-', '_')
end
# rubocop:disable Metrics/AbcSize
def plan
tag = replacer(name) + '_' + replacer(type)
<<~FIXTURE
#{tag}:
name: #{name}
type: #{type}
address: #{address}
FIXTURE
end
end
runner.rb
...
Legacy::Provider.all.each_with_index do |p, i|
p.extend(FixturePresenter)
f.puts p.plan
end
...
The address column in the plan table is a JSONB datatype. When we run this code this is the resulting YAML:
abc_plan_la_jolla:
name: ABC Plan La Jolla
type: default
address: {"street"=>"9888 Genesee Ave","unit"=>"","city"=>"La Jolla","state"=>"CA","postal_code"=>"92037"}
When you run your test you will get the very sad Syck error:
Psych::SyntaxError: (<unknown>): did not find expected ',' or '}' while parsing a flow mapping at line 4 column 12
The following change to the code will produce the correct YAML:
presenter.rb
address: #{address} to address: #{address.to_json}
The above change will produce a happy fixture definition:
abc_plan_la_jolla:
name: ABC Plan La Jolla
type: default
address: {"street":"9888 Genesee Ave","unit":"","city":"La Jolla","state":"CA","postal_code":"92037"}
Try
fixture_id:
existing_column: "foobar"
newly_added_column: "{\"reason\": \"foobar\"}"
I was maintaining a legacy Rails 4.2 application and needed to put JSON store value into a fixture. I made the following monkey patch to fix the problem. Hope this helps someone:
module ActiveRecord
class Fixture
def to_hash
h = fixture
model_class.attribute_names.each do |name|
typedef = model_class.type_for_attribute(name)
h[name] = typedef.coder.dump(h[name]) \
if typedef.is_a? ActiveRecord::Type::Serialized
end
h
end
end
end

Rails access hash value

I'm playing around with Netflix's Workflowable gem. Right now I'm working on making a custom action where the user can choose choices.
I end up pulling {"id":1,"value":"High"} out with #options[:priority][:value]
What I want to do is get the id value of 1. Any idea how to pull that out? I tried #options[:priority][:value][:id] but that seems to through an error.
Here's what the action looks like/how I'm logging the value:
class Workflowable::Actions::UpdateStatusAction < Workflowable::Actions::Action
include ERB::Util
include Rails.application.routes.url_helpers
NAME="Update Status Action"
OPTIONS = {
:priority => {
:description=>"Enter priority to set result to",
:required=>true,
:type=>:choice,
:choices=>[{id: 1, value: "High"} ]
}
}
def run
Rails.logger.debug #options[:priority][:value]
end
end
Here's the error:
Error (3a7b2168-6f24-4837-9221-376b98e6e887): TypeError in ResultsController#flag
no implicit conversion of Symbol into Integer
Here's what #options[:priority] looks like:
{"description"=>"Enter priority to set result to", "required"=>true, "type"=>:choice, "choices"=>[{"id"=>1, "value"=>"High"}], "value"=>"{\"id\":1,\"value\":\"High\"}", "user_specified"=>true}
#options[:priority]["value"] looks to be a strong containing json, not a hash. This is why you get an error when using [:id] (this method doesn't accept symbols) and why ["id"] returns the string "id".
You'll need to parse it first, for example with JSON.parse, at which point you'll have a hash which you should be able to access as normal. By default the keys will be strings so you'll need
JSON.parse(value)["id"]
I'm assuming the error is something like TypeError: no implicit conversion of Symbol into Integer
It looks like #options[:priority] is a hash with keys :id and :value. So you would want to use #options[:priority][:id] (lose the :value that returns the string).

Ruby Hash: can't convert String into Integer

I am new to Ruby, and I am having some problems with hashes.
I have XML returned from the YouTube API that I converted into a hash. Here is the hash returned by Hash.from_xml(): http://pastebin.com/9xxE6iXU
I am trying to grab specific elements from the hash for each result, such as the title, link, author, etc. Whenever I try to loop through the hash or grab a specific element, I receive a "can't convert String into Integer" error.
Here is the code I am using for the loop:
#data["feed"]["entry"]["title"].each do |key, value|
"<p>"+key+" "+value+"</p>"
end
I have also tried grabbing specific elements, such as #data["feed"]["entry"]["title"][0].
How do I loop through the hash and grab specific elements out?
That's happening because #data["feed"]["entry"] is array of hashes:
puts #data["feed"]["entry"].class # => Array
Each element-hash inside this array has "id", "category", "title" etc. values.
For grabbing each title try to use following snippet:
#data["feed"]["entry"].each do |entry|
puts entry["title"]
end
# => "TABE test adult basic education"
"WhatCollegesHopeYouWon'tFindOutAboutACTSATTestPrep..."
....

How do I serialize hash format:

I have the following data:
[{"uid"=>"12406664"}, {"uid"=>"13715056"}, {"uid"=>"20911274"}, {"uid"=>"20921750"}, {"uid"=>"144901695"}, {"uid"=>"200002261"}, {"uid"=>"583131545"}, {"uid"=>"584667098"}, {"uid"=>"585043552"}, {"uid"=>"593713530"}, {"uid"=>"645734146"}, {"uid"=>"649596998"}, {"uid"=>"663955553"}, {"uid"=>"698033741"}, {"uid"=>"1024899231"}, {"uid"=>"1032611215"}, {"uid"=>"1076202442"}, {"uid"=>"1168728549"}, {"uid"=>"1283882122"}, {"uid"=>"1296965460"}, {"uid"=>"1417999220"}, {"uid"=>"1420197620"}, {"uid"=>"1455766774"}, {"uid"=>"1479820827"}, {"uid"=>"1568075339"}, {"uid"=>"100000804563736"}, {"uid"=>"100001055926570"}, {"uid"=>"100001633945205"}]
How do I store this data using Ruby on Rails? I'd like to keep the data accesable, where
>> x[1]
=> {"uid"=>"13715056"}
Currently I'm using a postgreSQL heroku server, I have the User.user_id column serialized as a Hash and the data is a mess:
"[{\"uid\"=>\"12406664\"}, {\"uid\"=>\"13715056\"}, {\"uid\"=>\"20911274\"}, {\"uid\"=>\"20921750\"}, {\"uid\"=>\"144901695\"}, {\"uid\"=>\"200002261\"}, {\"uid\"=>\"583131545\"}, {\"uid\"=>\"584667098\"}, {\"uid\"=>\"585043552\"}, {\"uid\"=>\"593713530\"}, {\"uid\"=>\"645734146\"}, {\"uid\"=>\"649596998\"}, {\"uid\"=>\"663955553\"}, {\"uid\"=>\"698033741\"}, {\"uid\"=>\"1024899231\"}, {\"uid\"=>\"1032611215\"}, {\"uid\"=>\"1076202442\"}, {\"uid\"=>\"1168728549\"}, {\"uid\"=>\"1283882122\"}, {\"uid\"=>\"1296965460\"}, {\"uid\"=>\"1417999220\"}, {\"uid\"=>\"1420197620\"}, {\"uid\"=>\"1455766774\"}, {\"uid\"=>\"1479820827\"}, {\"uid\"=>\"1568075339\"}, {\"uid\"=>\"100000804563736\"}, {\"uid\"=>\"100001055926570\"}, {\"uid\"=>\"100001633945205\"}]"
>> User.last.uid.last
=> "]"
How can I correct this?
Thank you!
you can serialize as you wish: Hash, Array, custom class... you're quite free.
As of your expectations, serialize as an Array.

Resources