Mongoid::Contextual#each delegated to context.each, but context is nil - ruby

I have a Sinatra application connecting to MongoDB via Mongoid. It was working fine until a point where I started getting a weird error that I can't find anywhere on stackoverflow or anywhere.
Note that the same code is deployed on Heroku and it works fine with the same database version Mongo 3.0.7, ruby version 2.0.0 which I tried locally as well as 2.2.3. I get the error when I run shotgun through the web and when running Rspec:
Bible::Book#get_book_id is case-insensitive
Failure/Error: book[0]._id
Module::DelegationError:
Mongoid::Contextual#each delegated to context.each, but context is nil: #<Mongoid::Criteria
selector: {"title"=>"genesis"}
options: {}
class: Bible::Book
embedded: false>
# /Users/issa/.rvm/gems/ruby-2.2.3/gems/mongoid-5.0.0/lib/mongoid/contextual.rb:20:in `rescue in each'
# /Users/issa/.rvm/gems/ruby-2.2.3/gems/mongoid-5.0.0/lib/mongoid/contextual.rb:20:in `each'
# /Users/issa/.rvm/gems/ruby-2.2.3/gems/mongoid-5.0.0/lib/mongoid/criteria.rb:554:in `entries'
# /Users/issa/.rvm/gems/ruby-2.2.3/gems/mongoid-5.0.0/lib/mongoid/criteria.rb:554:in `method_missing'
# ./app/bible/book.rb:52:in `get_book_id'
# ./spec/bible/book_spec.rb:11:in `block (3 levels) in <top (required)>'
# ------------------
# --- Caused by: ---
# NoMethodError:
# undefined method `each' for nil:NilClass
# /Users/issa/.rvm/gems/ruby-2.2.3/gems/mongo-2.1.2/lib/mongo/cluster.rb:114:in `initialize'
My Rspec code:
RSpec.describe Bible::Book do
describe "#get_book_id" do
it "finds the id of genesis" do
expect(Bible::Book.get_book_id 'genesis').to eq 1
end
end
end
The code implementation is this:
module Bible
class Book
include Mongoid::Document
store_in collection: "bible_books"
field :title, type: String
field :testament, type: String
...
def self.get_book_id book_title
book = where(:title => book_title.downcase.strip)
return unless book
book[0]._id
end
end
end
My Gemfile has this part for MongoDB:
# MongoDB
...
gem 'mongoid', '~> 5.0'
gem 'bson_ext'
gem 'bson'
It's really strange that I get this error only on my machine, and just started out of the blue. I am using OS X El Capitan. I can access the mongodb collection from command line without issues and can run the same equivalent query to get the result I want:
> use bible
switched to db bible
> db.bible_books.find({"title": "genesis"})
{ "_id" : 1, "title" : "genesis", "testament" : "old", "chapters" : 50, "doc_type" : "book", "canon_type" : "canonical", "canon_order" : 1, "full_name" : { "en" : "The book of Genesis", "ar" : "سفر التكوين" }, "short_name" : { "en" : "Genesis", "ar" : "التكوين" }, "abbr_name" : { "ar" : "تك", "en" : "Gen" } }
I tried other collections, other queries, other variations, and still get the same error. I reverted to an older code from github that worked for sure, still the same issue, so it's clear to me that there's nothing wrong in my code or configuration. I tried different ruby versions from 2.0.0 - 2.2.3, different mongoid versions from 4 - 5 ... again the same versions of code and installation work fine on Heroku, but not my machine :(

I got similar error when wrong production configuration url was specified for mongoid: uri: <%= ENV['MONGOLAB_URI'] %>

I'm not sure if this is the source of your problem but I see a couple odd things in your get_book_id class method.
First of all, this will never leave book.nil?:
book = where(:title => book_title.downcase.strip)
That will leave you with a Mongoid::Contextual in book, the query may or may not find anything but book won't be nil in either case. That means that your:
return unless book
on the next line doesn't do anything useful. That also means that book[0] can be nil in here:
book[0]._id
You're also calling the _id method when you'd usually call id.
I think your method would be better off like this:
def self.get_book_id book_title
book = find_by(:title => book_title.downcase.strip)
return unless book
book.id
end
find_by(query) is just a short way of saying where(query).first so book = find_by(...) will leave you with a nil in book if it can't find anything and a single Bible::Book in book if it can find something.
If you have ActiveSupport available, you could also say:
find_by(:title => book_title.downcase.strip).try(:id)
to hide the nil check. You could also throw in an only call to only pull the _id out of MongoDB:
book = only(:id).find_by(:title => book_title.downcase.strip)
return unless book
book.id
# or, if ActiveSupport is around, just this:
only(:id).find_by(:title => book_title.downcase.strip).try(:id)

Related

How to customize cron job in ruby application?

I have been developing a backend with padrino ruby framework and I would like to build a cron job.
This is what I have done.
gem 'whenever', :require => false
wheneverize .
inside schedule.rb
every 1.minute do
rake "cronjob"
end
/tasks/cronjob.rake
Here I added my custom tasks. and this will be to long to add here.
So I wrote only error happening parts
performances = Performance.left_join(:slots, id: :slot_id).where(Sequel.~(status: ModelA::Api.settings.pending),Sequel[:slots][:from]>oneweekbefore,Sequel[:slots][:to]<onemonthafter+1.day)
....
begin
data = {}
data[:from] = "** <postmaster#**.mailgun.org>"
data[:to] = email
data[:subject] = subject
data[:html] = render 'mails/sendemailbasedontime',:locals => { :data => localdata }
RestClient.post GigabitArtist::Api.settings.mailgun_domain, data
rescue => exception
puts exception.inspect
end
end
I got these errors:
SEQUEL DEPRECATION WARNING: Passing multiple arguments as filter
arguments when not using a conditions specifier
([#:!=, #args=>[:status,
"pending"]>, #:>,
#args=>[#"slots",
#column=>:from>, Sat, 02 Dec 2017]>, #:<, #args=>[#"slots",
#column=>:to>, Wed, 10 Jan 2018]>]) is deprecated and will be removed
in Sequel 5. Pass the arguments to separate filter methods or use
Sequel.& to combine them.
/Users/whitesnow/.rvm/gems/ruby-2.4.1/gems/sequel-4.46.0/lib/sequel/dataset/query.rb:1296:in
filter_expr'
/Users/whitesnow/.rvm/gems/ruby-2.4.1/gems/sequel-4.46.0/lib/sequel/dataset/query.rb:1249:in
add_filter'
/Users/whitesnow/.rvm/gems/ruby-2.4.1/gems/sequel-4.46.0/lib/sequel/dataset/query.rb:1034:in
where'
/Volumes/Data/Work/RBP/GAB/tasks/cronjob.rake:12:inblock in '
/Users/whitesnow/.rvm/gems/ruby-2.4.1#global/gems/rake-12.0.0/lib/rake/task.rb:250:in
block in execute'
/Users/whitesnow/.rvm/gems/ruby-2.4.1#global/gems/rake-12.0.0/lib/rake/task.rb:250:in
each'
/Users/whitesnow/.rvm/gems/ruby-2.4.1#global/gems/rake-12.0.0/lib/rake/task.rb:250:in
execute'
/Users/whitesnow/.rvm/gems/ruby-2.4.1#global/gems/rake-12.0.0/lib/rake/task.rb:194:in
block in invoke_with_call_chain'
/Users/whitesnow/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/monitor.rb:214:in
mon_synchronize'
/Users/whitesnow/.rvm/gems/ruby-2.4.1#global/gems/rake-12.0.0/lib/rake/task.rb:187:in
invoke_with_call_chain'
I think errors are from sequel querying and
data[:html] = render 'mails/sendemailbasedontime',:locals => { :data => localdata }
ofcourse, this query was tested in other .rb file and I tested with raw sql. for example, I tested this tasks inside get request hander of test.rb controller. and it does work well
I would like to know if I can use render function inside task.
I searched all day for this problem with no success.
Any advice will be big help for me.
Thank you very much.
As the deprecation warning states, you are passing multiple arguments to a filter method. The simplest fix would be to call a filter method separately for each argument:
performances = Performance.
left_join(:slots, id: :slot_id).
exclude(status: ModelA::Api.settings.pending).
where(Sequel[:slots][:from]>oneweekbefore).
where(Sequel[:slots][:to]<onemonthafter+1.day)

Updating test case in rally by ruby

I am trying to update test case of a particular scenario. But it saying that undefined method update for :test_case symbol.
Need help on this..
My updating method is....
def dataValidInput(featName,testCase)
fields = {:workspace => #rally["workspace"],
:project => #rally["project"],
:work_product => featName,
:test_case => testCase,
:validation_input => #step_name,
:name => testCase}
test_case = #slm.update(:test_case,fields)
end
Am getting output as...
undefined method `update' for :test_case:Symbol (NoMethodError)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rally_rest_api-1.1.0/lib /rally_rest_api/rally_rest.rb:105:in `update'
C:/Users/CukesRally/features/CreateTC10.rb:176:in `nilValidInput'
C:/Users/CukesRally/features/CreateTC10.rb:154:in `chek_Steps'
C:/Users/CukesRally/features/CreateTC10.rb:132:in `find_or_create_test_case'
C:/Users/CukesRally/features/CreateTC10.rb:104:in `after_features'
C:/Users/CukesRally/features/CreateTC10.rb:93:in `before_test_case'
My Command :
cucumber C:/Users/CukesRally/features/Plan.feature --format MyTest::CreateStep
Thanks
First of all, I see that you're using an outdated gem. Please switch to using the rally_api gem. The latest version is 1.1.2: https://rubygems.org/gems/rally_api/versions/1.1.2
Then, if you still need help, please point me to a repo where the code is located or provide a gist link. I'd like to know where #slm and :work_product are defined as they seem to be the source of your error.

Confusion with Ruby to save the files with any extensions to the excel columns

I am creating a script to insert the files from folders to the Excel columns, but it seems I am doing wrong. Can any one help me for the same?
updated Ruby Code:
require 'fileutils'
require 'win32ole'
#Excel Application will be started from here.
#--------------------------------------------
excel = WIN32OLE.new('Excel.Application')
excel.visible = true
wb=excel.workbooks.open("E:\\WIPData\\Ruby\\Scripts\\Copy of GSL_File_DownLoad1.xlsx")
wbs= wb.Worksheets(1)
rows=2
column=2
until wbs.cells(rows,1).value == nil do
Dir.entries("E:\\WIPData\\Ruby").each do |f|
if f == wbs.cells(rows,1).value then
files_dir = File.expand_path("..", Dir.pwd)
column=2
Dir.foreach(files_dir.concat("/" + f)) do |x|
full_path=files_dir.concat("/" + x)
wbs.cells(rows,column).Select
wbs.oleobjects.add({
'Filename' => full_path,
'Link' => true,
'DisplayAsIcon' => false,
})
column = column + 1
end
break
end
end
end
wb.Save
wb.Close(0)
excel.Quit()
#Excel Application will be finished here.
#------------
Error:
E:/WIPData/Ruby/Scripts/test.rb:27:in `method_missing': (in OLE method `add': )
(WIN32OLERuntimeError)
OLE error code:800A03EC in Microsoft Excel
Cannot insert object.
HRESULT error code:0x80020009
Exception occurred.
from E:/WIPData/Ruby/Scripts/test.rb:27:in `block (2 levels) in <main>'
from E:/WIPData/Ruby/Scripts/test.rb:23:in `foreach'
from E:/WIPData/Ruby/Scripts/test.rb:23:in `block in <main>'
from E:/WIPData/Ruby/Scripts/test.rb:17:in `each'
from E:/WIPData/Ruby/Scripts/test.rb:17:in `<main>'
Your problem is on line 25 in your code. It is the method wbs.OLEObjects.Add(,full_path,False,True,,,f) that is causing the problem.
In VBA, it is perfectly fine to leave parameters to a method blank if they are not required. However, this is not available in Ruby.
In your original Macro, you passed keyword arguments to the method. One way of doing this in Ruby is with a Hash. An article on the Ruby on Windows blog suggests doing it like so:
wbs.oleobjects.add({
'Filename' => full_path,
'Link' => false,
'DisplayAsIcon' => true,
'IconIndex' => 0,
'IconLabel' => f,
'IconFileName' => icon_path
})
I did not see you provide an icon path in your Ruby code so I'm making an assumption on that final variable.
Also note that true and false are lowercase. Uppercase versions would be read by Ruby as either a constant or a class.
If you are doing work in Microsoft Office with Ruby, I would highly recommend frequenting Ruby on Windows. The author doesn't appear to post anymore but it is still a relevant source.
EDIT:
Your new error is probably due to Dir.entries. This method will grab . and .. when it pulls entries. I'd imagine Excel is tripping up on trying to add those two to the Worksheet.
There are two ways to remove this.
1) Skip them in your each block.
Dir.entries("E:\\WIPData\\Ruby").each do |f|
next if ['.', '..'].include? f
# The rest of your block code
end
2) Use Dir#glob which will not return . and ..
Dir.chdir("E:\\WIPData\\Ruby")
Dir.glob('*').each do |f|
# Your block code
end
EDIT:
For documentation's sake, this topic is also discussed on Ruby Forums.

Authlogic doesn't work with my Rails 3.2 app

I'm running Rails 3.2 and the latest version of Authlogic. When I run my app locally on my Mac, it works fine. When I try to run it on my production server (Ubuntu with Passenger/Apache), I get this:
You must establish a database connection before using acts_as_authentic
I'm not sure how to troubleshoot the problem. I posted this related question earlier today before I realized that the problem was broader than I thought.
I figured out the problem. Look at this snippet from Authlogic's lib/authlogic/acts_as_authentic/base.rb:
private
def db_setup?
begin
column_names
true
rescue Exception
false
end
end
If column_names throws an error, db_setup? will return false. Look at this other function, also from base.rb:
def acts_as_authentic(unsupported_options = nil, &block)
# Stop all configuration if the DB is not set up
raise StandardError.new("You must establish a database connection before using acts_as_authentic") if !db_setup?
raise ArgumentError.new("You are using the old v1.X.X configuration method for Authlogic. Instead of " +
"passing a hash of configuration options to acts_as_authentic, pass a block: acts_as_authentic { |c| c.my_option = my_value }") if !unsupported_options.nil?
yield self if block_given?
acts_as_authentic_modules.each { |mod| include mod }
end
If db_setup? returns false, Authlogic will throw an exception, but not the same exception thrown by column_names.
My problem was that column_names was throwing this exception:
/Users/jason/.rvm/gems/ruby-1.9.2-p180/gems/activerecord-3.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:1106:in `async_exec': PG::Error: ERROR: relation "users" does not exist (ActiveRecord::StatementInvalid)
LINE 4: WHERE a.attrelid = '"users"'::regclass
^
: SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull
FROM pg_attribute a LEFT JOIN pg_attrdef d
ON a.attrelid = d.adrelid AND a.attnum = d.adnum
WHERE a.attrelid = '"users"'::regclass
AND a.attnum > 0 AND NOT a.attisdropped
ORDER BY a.attnum
And the reason for THAT exception is that my user table is called user, not users, but Rails was not picking up on my pluralize_table_names setting properly. Once I fixed my pluralize_table_names problem (apparently the way this setting works has been changed in Rails 3.1), my Authlogic problem went away.
So if you're having this problem, you might want to try this:
Clone the Authlogic repo to somewhere on your dev machine
Change your Gemfile to use the local version of Authlogic ('authlogic', :path => '/path/to/authlogic')
Add a column_names call to db_setup? outside the begin/rescue/end clause
See if you get a different, potentially more accurate and informative, error, like I did
I've fixed this on my fork. Until Ben has time to merge the fix you can work around this using the fixed branch in your Gemfile;
gem 'authlogic', :git => 'git#github.com:james2m/authlogic.git', :branch => 'fix-migrations'
For anyone else who might have come to this page looking for an answer.
One reason could be that your haven't created your test database.
Just run:
$ RAILS_ENV=test rake db:create db:migrate
Follow the open issue at https://github.com/binarylogic/authlogic/issues/318 and +1 so the fix gets merged soon :)

Cannot find Document with Ruby and MongoDB when using ObjectId

I have some code written in Ruby 1.9.2 patch level 136 and I'm have an issue where when I perform a find via the _id in the raw ruby mongo driver I get a nil when trying to use a value from a csv file. Here's the code:
require 'mongo'
require 'csv'
require 'bson'
# Games database
gamedb = Mongo::Connection.new("localhost", 27017).db("gamedb")
#games = gamedb.collection("games")
# Loop over CSV data.
CSV.foreach("/tmp/somedata.csv") do |row|
puts row[0] # Puts the ObjectId
#game = #games.find( { "_id" => row[0] } ).first
puts #game.inspect
end
The CSV file looks like this:
_id,game_title,platform,upc_db_match,upc
4ecdacc339c7d7a2a6000002,TMNT,PSP,TMNT,085391157663
4ecdacc339c7d7a2a6000004,Super Mario Galaxy,Wii,Super Mario Galaxy,045496900434
4ecdacc339c7d7a2a6000005,Beowulf,PSP,Beowulf,097363473046
The first column is the objectId in Mongo that I already have. If I perform a local find from the mongo command line the values in the first column, I get the data I want. However, the code above returns nil on the #game.inspect call.
I've tried the following variations, which all produce nil:
#game = #games.find( { "_id" => row[0].to_s } ).first
#game = #games.find( { "_id" => row[0].to_s.strip } ).first
I've even tried building the ObjectId with the BSON classes as such:
#game = #games.find( { "_id" => BSON::ObjectId(row[0]) } ).first
or
#game = #games.find( { "_id" => BSON::ObjectId("#{row[0]}") } ).first
Both of which output the following error:
/Users/donnfelker/.rvm/gems/ruby-1.9.2-p136#upc-etl/gems/bson-1.4.0/lib/bson/types/object_id.rb:126:in `from_string': illegal ObjectId format: _id (BSON::InvalidObjectId)
from /Users/donnfelker/.rvm/gems/ruby-1.9.2-p136#upc-etl/gems/bson-1.4.0/lib/bson/types/object_id.rb:26:in `ObjectId'
from migrate_upc_from_csv.rb:14:in `block in <main>'
from /Users/donnfelker/.rvm/rubies/ruby-1.9.2-p136/lib/ruby/1.9.1/csv.rb:1768:in `each'
from /Users/donnfelker/.rvm/rubies/ruby-1.9.2-p136/lib/ruby/1.9.1/csv.rb:1202:in `block in foreach'
from /Users/donnfelker/.rvm/rubies/ruby-1.9.2-p136/lib/ruby/1.9.1/csv.rb:1340:in `open'
from /Users/donnfelker/.rvm/rubies/ruby-1.9.2-p136/lib/ruby/1.9.1/csv.rb:1201:in `foreach'
from migrate_upc_from_csv.rb:10:in `<main>'
The crazy thing is, if I manually create the BSON ObjectId by hand it works (as shown below):
#game = #games.find( { "_id" => BSON::ObjectId("4ecdacc339c7d7a2a6000004") } ).first
When I run #game.inspect I get my data back, as I would expect. However, If I change this to use row[0], I get nil.
Why? What am I doing wrong?
System Details
$ gem list
*** LOCAL GEMS ***
bson (1.4.0)
bson_ext (1.4.0)
mongo (1.4.0)
RVM Version: rvm 1.6.9
Ruby Version: ruby 1.9.2p136 (2010-12-25 revision 30365) [x86_64-darwin10.6.0]
Mongo Version:
[initandlisten] db version v1.8.2, pdfile version 4.5
[initandlisten] git version: 433bbaa14aaba6860da15bd4de8edf600f56501b
Again, why? What am I doing wrong here? Thanks!
The first row is not being read as a header, to do that pass in :headers => true like this:
require 'csv'
# Loop over CSV data.
CSV.foreach("/tmp/somedata.csv", :headers => true) do |row|
puts row[0] # Puts the ObjectId
end
If you do not pass the :headers parameter in you can see the first row[0] object is the string "_id":
_id
4ecdacc339c7d7a2a6000002
4ecdacc339c7d7a2a6000004
4ecdacc339c7d7a2a6000005
When you include it, you are golden:
4ecdacc339c7d7a2a6000002
4ecdacc339c7d7a2a6000004
4ecdacc339c7d7a2a6000005
Are you sure your CSV parsing code isn't treating the headers as a first line of data and actually tries to do BSON::ObjectId("_id")? The error message kinda looks like it. Try with FasterCSV.foreach('/tmp/somedata.csv', :headers => true) and using row['_id'] (IIRC you'll still have to use BSON::ObjectID).

Resources