Undefined method `collection' for #<Mongo::Client> Did you mean? collections (NoMethodError). Ruby - ruby

I am working with automated test. This is the first time I'm working with mongoDB.
So, I am trying to create a generic method to find a document in a desired collection that will be passed as parameter. I've found some examples and all of them use the .collection method. It doesn't seem to work in my project.
Here's my DB client code:
require 'mongo'
require 'singleton'
class DBClient
include Singleton
def initialize
#db_connection = Mongo::Client.new($env['database']['feature']['url'])
end
def find(collection, value)
coll = #db_connection.collection(collection)
coll.find(owner: 'value')
end
end
And here's how I instance my method
DBClient.instance.find('collectionTest', 'Jhon')
When I run my test I get the following message:
undefined method `collection' for #<Mongo::Client: cluster=localhost:>
Did you mean? collections (NoMethodError)
The gem I'm using is mongo (2.6.1).
What I am doing wrong?

Based on documentation, there is indeed no method collection in Mongo::Client. What you are looking for is the [] method. The code will then look like this:
require 'mongo'
require 'singleton'
class DBClient
include Singleton
def initialize
#db_connection = Mongo::Client.new($env['database']['feature']['url'])
end
def find(collection, value)
coll = #db_connection[collection]
coll.find(owner: value)
end
end
EDIT: I've also changed the line with the find itself. In your original code, it would find documents where owner is 'value' string. I presume you want the documents where owner matches the value send to the function.

Related

What is the method called when the URI('http://google.com') start?

Almost all of you used URI module to convert a url string to an object in order to make some validation or change.
Example:
require 'uri'
URI('https://google.com')
# => #<URI::HTTPS https://google.com>
As you can see, the result is the HTTPS object under the URI module.
So, there is a question what is run when you write module/class name with round braces like the line of code above.
I thought, it is implicit calling of call method, but I got NoMethodError.
Example:
class MyClass
def self.call
puts 'You were right!'
end
end
MyClass()
# => NoMethodError: undefined method `MyClass' for main:Object
Funny enough, with the code you've shown, MyClass.() works (which is an alias for .call).
However in the case of URI, this actually a method (methods can begin with capitals). You can see the source code here: https://apidock.com/ruby/Kernel/URI/instance

How to create and call parameterised page-object classes

I am using page-factory visit, on methods to call page-object classes from spec file in ruby. I would like know how to parameterise page-object classes, passing parameters from spec file using page factory methods.
I want to log all steps information in page-object class. To do this, I created a log in spec file using the logger gem. I need to pass the log object as input parameter to page classes to capture data. Here is the code I am using to do this.
spec file that calling page class:
require './lib/pages/Test_page'
file="logs/uniusecase_#{#ncs_server['build_no']}_#{#ncs_server['test_type']}_#{time}.log"
$log=Logger.new(file)
describe 'testcase-1',:sanity do
visit Testpage, using_params: {logger: $log} do |page|
end
end
page-object class:
class Testpage
include PageObject
log = "<%=params[:logger]%>"
def goto
log ("test msg-1")
end
def testmethod()
log("test msg -2")
end
end
I am getting "NameError: undefined local variable or method `log' error message while execution. Could somebody help me in doing this?
The :using_params are stored in the class' #merged_params variable. You can get this variable by doing:
self.class.instance_variable_get(:#merged_params)
So your method would look something like:
def goto
logger = self.class.instance_variable_get(:#merged_params)[:logger]
logger("test msg-1")
end
However, if you are defining the logger in a global variable, it will already be available to the page object class (ie you do not need to pass it along). In other words, you could simply do:
def goto
$log ("test msg-1")
end

ruby: calling a instance method without using instance

I know in ruby, when we call an instance method, we need to firstly instantiate a class object.
But when I see a open sourced code I got confused.
The code is like this:
File Message.rb
require 'json'
module Yora
module Message
def serialize(msg)
JSON.generate(msg)
end
def deserialize(raw, symbolized_key = true)
msg = JSON.parse(raw, create_additions: true)
if symbolized_key
Hash[msg.map { |k, v| [k.to_sym, v] }]
else
msg
end
end
end
end
File. Persistance.rb
require 'fileutils'
require_relative 'message'
module Yora
module Persistence
class SimpleFile
include Message
def initialize(node_id, node_address)
#node_id, #node_address = node_id, node_address
FileUtils.mkdir_p "data/#{node_id}"
#log_path = "data/#{node_id}/log.txt"
#metadata_path = "data/#{node_id}/metadata.txt"
#snapshot_path = "data/#{node_id}/snapshot.txt"
end
def read_metadata
metadata = {
current_term: 0,
voted_for: nil,
cluster: { #node_id => #node_address }
}
if File.exist?(#metadata_path)
metadata = deserialize(File.read(#metadata_path)) #<============
end
$stderr.puts "-- metadata = #{metadata}"
metadata
end
.....
You can see the line I marked with "<==="
It uses deserialize function that been defined in message class.
And from message class we can see that method is a instance method, not class method.
So why can we call it without instantiating anything like this?
thanks
Message ist an module. Your Class SimpleFile includes this module. so the module methods included in your class SimpleFile. that means, all module methods can now be used like as methods from SimpleFile
see http://ruby-doc.org/core-2.2.0/Module.html for more infos about module in ruby. it's a great feature.
It is being called on an instance. In Ruby, if you leave out the explicit receiver of the message send, an implicit receiver of self is assumed. So, deserialize is being called on an instance, namely self.
Note that this exact same phenomenon also occurs in other places in your code, much earlier (in line 1, in fact):
require 'fileutils'
require_relative 'message'
Here, you also have two method calls without an explicit receiver, which means that the implicit receiver is self.

ruby, no method error

I am receiving the following error when running my below ruby script:
s3parse.rb:12:in `block in <class:AccountLog>': undefined method `extract_account_id' for AccountLog:Class (NoMethodError)
I dont think it should be a class method, is there a reason its not taking my method into account?
class AccountLog
attr_accessor :bytes, :account_id, :date
def extract_account_id(line)
line.match(%r{accounts/(\d+)}).captures.join.to_i
end
s3log = File.open('vidcoder.txt').each do |line|
account_log = AccountLog.new
account_log.date = line.match(%r{\[[^:]*}).to_s.delete"[" #need to finish this regex to make it work
account_log.account_id = extract_account_id(line)
account_log.bytes = line.match(%r{^.*\s+HTTP.*\s+-\s+(\d+)\s+}).captures.join.to_i
puts "\n"
puts "The api request on #{account_log.date} was fromm account number #{account_log.account_id} and the bytes were #{account_log.bytes}"
end
end
def extract_account_id will define an instance method.
In the way you call it, you need a class method instead.
Define it like this:
def self.extract_account_id(line)
or, as you already have an AccountLog instance, use it to call extract_account_id:
account_log.account_id = account_log.extract_account_id(line)
Please note that with second way you do not need to alter method definition, just call extract_account_id via account_log instance.
And i guess you would want to put s3log = File... outside class definition.
Or use a constant instead: S3log = ...
Then you'll can access it as AccountLog::S3log
Is there any reason you don't think it should be a class method? You are using it in the context of a class method and that's why it it's saying no such method for class AccountLog.
If you name your method as self.extract_account_id(line) I'm sure it will work.
From what you are trying to do I think this is what you are looking for?
class AccountLog
attr_accessor :bytes, :account_id, :date
def self.extract_account_id(line)
line.match(%r{accounts/(\d+)}).captures.join.to_i
end
end
s3log = File.open('vidcoder.txt').each do |line|
account_log = AccountLog.new
account_log.date = line.match(%r{\[[^:]*}).to_s.delete"[" #need to finish this regex to make it work
account_log.account_id = extract_account_id(line)
account_log.bytes = line.match(%r{^.*\s+HTTP.*\s+-\s+(\d+)\s+}).captures.join.to_i
puts "\n"
puts "The api request on #{account_log.date} was fromm account number #{account_log.account_id} and the bytes were #{account_log.bytes}"
end
While you could take the class method approach, there seems to be a little more going on.
You should put the extraction logic in a method in itself rather than let it hangout in your class. Then outside of the class, have an instance of AccountLog where you can call on the methods for log and account id extraction. At that point you can do something with those values.
Class method or not is a detail we can explore after the class is a bit more clean I think.

Adding #to_yaml to DataMapper models

I am using DataMapper for Database access. My goal is to send the models to an webservice as read-only object. This is my current try:
class User
include DataMapper::Resource
def to_yaml(opts = {})
mini_me = OpenStruct.new
instance_variables.each do |var|
next if /^#_/ =~ var.to_s
mini_me.send("#{var.to_s.gsub(/^#/, '')}=", instance_variable_get(var))
end
mini_me.to_yaml(opts)
end
....
end
YAML::ENGINE.yamler = 'psych'
u = User.get("hulk")
p u.to_yaml
# => "--- !ruby/object:OpenStruct\ntable:\n :uid: hulk\n :uidNumber: 1000\n :gidNumber: 1001\n :email: hulk#example.com\n :dn: uid=hulk,ou=People,o=example\n :name: Hulk\n :displayName: Hulk\n :description: Hulk\n :homeDirectory: /home/hulk\n :accountFlags: ! '[U ]'\n :sambaSID: S-1-5-21-......\nmodifiable: true\n"
p [ u ].to_yaml # TypeError: can't dump anonymous class Class
Any ideas how to make this work and get rid of the exception?
Thanks,
krissi
Using to_yaml is deprecated in Psych, and from my testing it seems to be actually broken in cases like this.
When you call to_yaml directly on your object, your method gets called and you get the result you expect. When you call it on the array containing your object, Psych serializes it but doesn’t correctly handle your to_yaml method, and ends up falling back onto the default serialization. In your case this results in an attempt to serialize an anonymous Class which causes the error.
To fix this, you should use the encode_with method instead. If it’s important that the serialized form is tagged as an OpenStruct object in the generated yaml you can use the represent_object (that first nil parameter doesn’t seem to be used):
def encode_with(coder)
mini_me = OpenStruct.new
instance_variables.each do |var|
next if /^#_/ =~ var.to_s
mini_me.send("#{var.to_s.gsub(/^#/, '')}=", instance_variable_get(var))
end
coder.represent_object(nil, mini_me)
end
If you were just using OpenStruct for convenience, an alternative could be something like:
def encode_with(coder)
instance_variables.each do |var|
next if /^#_/ =~ var.to_s
coder[var.to_s.gsub(/^#/, '')]= instance_variable_get(var)
end
end
Note that Datamapper has its own serializer plugin that provides yaml serialization for models, it might be worth looking into.

Resources