How to load yaml with ruby 2.1 - ruby-on-rails

I have a the following data in tmp.yml. My goal is to load the data to mysql database.
I have the following code to load the data from tmp.yml:
$LOAD_PATH.unshift( File.join( File.dirname(__FILE__), 'lib' ) )
require 'yaml'
require 'AacflmDirection' # Just an empty class
SITE_PATH = '/var/www/test/testme/asian_cinema/tmp.yml'
doc = YAML::load( File.open( SITE_PATH ) )
puts doc[0]['attributes']['position'] # Expect position = 1
And I got this error. It seems I cannot access it via hash.
load.rb:8:in `<main>': undefined method `[]' for #<AacflmDirection:0x000000023c9fe0> (NoMethodError)
tmp.yml
--- !ruby/object:AacflmDirection
attributes:
position: "1"
film_id: "1"
created_on: 2012-02-06 09:31:31
page_id: "2671"
director_id: "1"
id: "1"
site_id: "173"
director:
film:
page:
site:
--- !ruby/object:AacflmDirector
assets:
attributes:
slug: paul-cox
name: Paul Cox
bio_markup: ""
created_on: 2012-02-06 09:31:39
page_id: "2671"
id: "51"
bio:
site_id: "173"
directions:
draft:
films:
page:
pathprints:
settings_objects:
site:

You're unserializing objects, not hashes. doc[0] is an instance of AacflmDirection. You need to access them with whatever accessors they provide.
Try doc[0].position.

First, three hyphens --- separate multiple documents in yaml. Then the !ruby/object... followed will deserialize your file to an object, not hash.
In your original code, you only get the AacflmDirection object as your doc variable. Use YAML::load_stream to load all the objects in your yaml.
require 'AacflmDirector'
require 'AacflmDirection'
doc = YAML::load_stream( File.open( SITE_PATH ) )
By that you'll get:
=> [#<AacflmDirection:0x007fa62c1c3a48
#attributes=
{"position"=>"1",
"film_id"=>"1",
"created_on"=>2012-02-06 17:31:31 +0800
"page_id"=>"2671",
"director_id"=>"1",
"id"=>"1",
"site_id"=>"173"},
#director=nil,
#film=nil,
#page=nil,
#site=nil>,
#<AacflmDirector:0x007fa62c1bbe10
#assets=nil,
#attributes=
{"slug"=>"paul-cox",
"name"=>"Paul Cox",
"bio_markup"=>"",
"created_on"=>2012-02-06 17:31:39 +0800,
"page_id"=>"2671",
"id"=>"51",
"bio"=>nil,
"site_id"=>"173"},
#directions=nil,
#draft=nil,
#films=nil,
#page=nil,
#pathprints=nil,
#settings_objects=nil,
#site=nil>]
Then add attr_accessor :attributes in your AacflmDirection class defination. So you can get the value by:
doc[0].attributes["position"]

Use YAML::load_file(SITE_PATH) to read the file and convert it to a Ruby object.

Related

Rails rspec CSV generator error for array of string in response

I've got specs for my CSV generator
RSpec.describe CsvAdminLogData::CsvAdminLogGenerator do
include_context 'with admin_user form'
subject(:csv_file) { described_class.new(start_date, end_date).call }
it 'creates CSV file with proper value' do
csv_file
log_file = CSV.open('app/custom/file.csv')
expect(log_file.to_a[1]).to match_array(
CSV.generate_line([
admin_log1.created_at,
admin_log1.action_type,
admin_log1.admin_email,
admin_log1.old_data,
admin_log1.new_data,
]),
)
end
With error:
expected collection contained: ["2019-06-17 16:39:22 +0200,New,orlandoratke#cruickshankmclaughlin.info,\"{\"\"email\"\"=>\"\"courtne...=>\"\"2019-09-16T16:39:22.880+02:00\"\", \"\"other_activities\"\"=>\"\"forbidden websites\"\"}\"\n"]
actual collection contained: ["2019-06-17 16:39:22 +0200", "New", "orlandoratke#cruickshankmclaughlin.info", "{\"email\"=>\"courtn... \"last_update\"=>\"2019-09-16T16:39:22.880+02:00\", \"other_activities\"=>\"forbidden websites\"}"]
the missing elements were: ["2019-06-17 16:39:22 +0200,New,orlandoratke#cruickshankmclaughlin.info,\"{\"\"email\"\"=>\"\"courtne...=>\"\"2019-09-16T16:39:22.880+02:00\"\", \"\"other_activities\"\"=>\"\"forbidden websites\"\"}\"\n"]
the extra elements were: ["2019-06-17 16:39:22 +0200", "New", "orlandoratke#cruickshankmclaughlin.info", "{\"email\"=>\"courtn... \"last_update\"=>\"2019-09-16T16:39:22.880+02:00\", \"other_activities\"=>\"forbidden websites\"}"]
So as far I see I've got an array of string instead of just an array. I was trying to handle it with something like this:
log_file = CSV.open('app/custom/file.csv').to_a
expect([log_file[1].join(',')])
But without results. I also tried to add ([... admin_log1.new_data,]).first.split(', ') at the end of expected results but I received an error NoMethodError: undefined method split' for Mon, 17 Jun 2019 16:14:56 CEST +02:00:Time
expect(log_file.to_a[1]).to match_array([
admin_log1.created_at,
admin_log1.action_type,
admin_log1.admin_email,
admin_log1.old_data,
admin_log1.new_data])
log_file will be something like [['a', 'b', 'b'], [...], ...].
By using CSV.generate_row you are converting the Array back to a String.
I don't suggest doing this but if you where just reading the file instead of parsing it you could use generate_line to create a String and compare it, as such:
csv = File.read('...')
.each_line
.drop(1) # remove header row
expect(csv[0]).to eq(CSV.generate_line([1,2,3])

Rails 5: How do I point fixtures to other fixtures?

I three models Comment, User and Project. Project and Comment need to point to other objects in order to be valid. For example, a comment needs to point to an author (user) and a project.
The associated fixture files look like this:
# comments.yml
test_comment:
author: users(:test_user)
project: projects(:test_project)
# users.yml
test_user:
name: 'test user'
# projects.yml
test_project:
name: 'Test'
description: 'This is a test'
owner: users(:test_user)
However, I've found that my fixtures are probably set up incorrectly. Rails returns false if I try to save the comment:
assert_equal true, comments(:test_comment)
#=> false
I can see that there are foreign keys for a project and author:
=> #<Comment:0x00007f9b1661f3d8
id: 137725605,
body: "",
project_id: 745075726,
author_id: "31ceee04-5307-5059-91db-0dc2068a780c",
created_at: Fri, 22 Feb 2019 13:17:58 UTC +00:00,
updated_at: Fri, 22 Feb 2019 13:17:58 UTC +00:00>
But when I interrogate them, Rails returns nil.
> comments(:test_comment).author
=> nil
> comments(:test_comment).project
=> nil
I expected that one would return users(:test_user) and the other would return projects(:test_project). I thought perhaps I needed to use ERB in my yaml:
test_comment:
author: <%= users(:test_user) %>
project: <%= projects(:test_project) %>
But that results is a stream of errors when I run my tests:
NoMethodError: undefined method `users' for #<#<Class:0x00007f9b17692ff8>:0x00007f9b17692dc8>
What do I need to do to point fixtures to other fixtures? Can it be done? What have I done wrong?
In the Rails guide on Testing with YAML fixtures, you can see that you don't need users(:test_user) to refer to some other object. Instead, you can simply write test_user:
# comments.yml
test_comment:
author: test_user
project: test_project
# users.yml
test_user:
name: 'test user'
# projects.yml
test_project:
name: 'Test'
description: 'This is a test'
owner: test_user
Hope this helps!

Renaming field in Mongoid does not update field in class

When I rename a field in Mongoid, it successfully updates the field in MongoDB, but it does not update the field in the ruby code:
class Example
include Mongoid::Document
field :apple, type: String, as: :c_apple
end
Example.all
=> #<Mongoid::Criteria
selector: {}
options: {}
class: Example
embedded: false>
Example.all.rename("apple" => "d_apple")
MOPED: 127.0.0.1:27017 UPDATE database=core collection=examples selector={} update={"$rename"=>{"apple"=>"d_apple"}} flags=[:multi]
COMMAND database=core command={:getlasterror=>1, :w=>1} runtime: 1.2460ms
=> {"connectionId"=>2, "updatedExisting"=>false, "n"=>0, "syncMillis"=>0, "writtenTo"=>nil, "err"=>nil, "ok"=>1.0}
e = Example.new
=> #<Example _id: 5bfdbf103ed1492f9a000001, apple(c_apple): nil>
e.d_apple
NoMethodError: undefined method `d_apple' for #<Example _id: 5bfdbf103ed1492f9a000001, apple(c_apple): nil>
Why are the changes in MongoDB not reflected in class definition?
When you run #rename, you interact with MongoDB. The change of document structure is stored in the database. This method does not interact with ruby source code, you need to edit it by yourself.
Btw. I can't recall any ruby/rails method (besides ones in rake tasks and generators) that interacts with the source code stored in files.

Improper indentation in converting ruby hash to yaml

I am trying to convert ruby hash object to YAML format using YAML.dump(obj) but I am getting improper indentation even after using dump options.
I have below executable ruby script :
#!/usr/bin/ruby
require "yaml"
require "erb"
context_path = ARGV[0]
context = YAML.load_file(context_path)['context']
def get_yaml(obj)
YAML.dump( obj['imports']['external_repositories']['credentials'] ).sub(/.*?\n/,'')
end
The value of - obj['imports']['external_repositories']['credentials'] is
{"iacbox"=>{"basic"=>{"name"=>"", "password"=>""}}, "nexus"=>{"basic"=>{"name"=>"cpreader", "password"=>"swordfish"}}}
Note : I used the sub method to remove "---" at the start of the output
The ERB template calls the above get_yaml method as :
credentials:
<%= get_yaml( context ) %>
The output that is coming is :
credentials:
iacbox:
basic:
name: ''
password: ''
nexus:
basic:
name: cpreader
password: swordfish
while I am expecting the output as :
credentials:
iacbox:
basic:
name: ''
password: ''
nexus:
basic:
name: cpreader
password: swordfish
How can I get the expected output from a dump?
I think the easiest thing for you to do here is just put the credentials key also in the Hash, i.e. change your template snippet so that it is one line:
<%= get_yaml( context ) %>
And change your get_yaml method to be:
def get_yaml(obj)
YAML.dump({'credentials' => obj['imports']['external_repositories']['credentials']})
.sub(/.*?\n/,'')
end
If that doesn't work for you, for example, if you have additional keys underneath the credentials key that you haven't mentioned, you could also do something like this:
def get_yaml(obj)
YAML.dump(obj['imports']['external_repositories']['credentials'])
.sub(/^---\n/,'')
.gsub(/\n/m,"\n ")
end
Where gsub(/\n/m,"\n ") replaces all newlines with a newline plus two spaces.

MongoMapper - Updating existing records with new keys

When adding a key to an existing model (with existing data) via MongoMapper, I can create new documents with the new key but when trying to access existing documents using that same key it fails stating that it's an "undefined method."
I was wondering if anyone had any insight.
Thanks in advance!
(Yes, these examples are truncated.)
- model.rb -
key :key_1
key :key_2
- would return -
#<Model _id: BSON::ObjectID('4ba821abebddb9094c000001'), key_1: "test", key_2: "test">
- model.rb (updated version) -
key :key_1
key :key_2
key :key_3
- would still only return -
#<Model _id: BSON::ObjectID('4ba821abebddb9094c000001'), key_1: "test", key_2: "test">
- but if a new doc is created -
#<Model _id: BSON::ObjectID('4ba821abebddb9094c000001'), key_1: "test", key_2: "test">
#<Model _id: BSON::ObjectID('7ba131abedaab9094c007482'), key_1: "test", key_2: "test", key_3: "test">
This would be fine except for the fact that I receive a method undefined error when trying to access :key_3 for the first document.
Rails 2.3.4
MongoMapper 0.7.4
I'm not seeing this behavior at all, even when interacting with an object instantiated before I updated the class. When running the following in irb, I have no errors:
>> gem 'mongo_mapper', '0.7.4'
=> true
>> require 'mongo_mapper'
=> true
>> MongoMapper.database = 'test'
=> "test"
>> class Foo
>> include MongoMapper::Document
>> key :something
>> end
=> #<MongoMapper::Plugins::Keys::Key:0x101f8f938 #default_value=nil, #type=nil, #name="something", #options={}>
>> f = Foo.new(:something => 'thing')
=> #<Foo _id: ObjectID('4c4dc9af712337447c000001'), something: "thing">
>> f.save
=> true
>> f
=> #<Foo _id: ObjectID('4c4dc9af712337447c000001'), something: "thing">
>> class Foo
>> key :something_else
>> end
=> #<MongoMapper::Plugins::Keys::Key:0x101f6ad90 #default_value=nil, #type=nil, #name="something_else", #options={}>
>> f
=> #<Foo something_else: nil, _id: ObjectID('4c4dc9af712337447c000001'), something: "thing">
>> f.something_else
=> nil
Since it seems like you're having an unusual problem, more details of your use-case would be helpful. Could you please give us a more complete code example? If you've got proprietary stuff in the code that's failing, pare it down to the minimum case required to still have it fail and post the complete declarations of your models and the code you're using to access them.
Use the set command...
#model.set(:key_3 => "VALUE...")
#model.reload
#model.key_3 # => "VALUE..."
#model.save
This code will create a new field for your model, confirm that you already did defined with the new key:
key :key_3
Enjoy,

Resources