Mongoid :: Contextual#每个委托给context.each,但context是nil

时间:2015-12-27 23:54:23

标签: ruby mongodb sinatra mongoid

我有一个通过Mongoid连接到MongoDB的Sinatra应用程序。它工作正常,直到我开始得到一个奇怪的错误,我无法在stackoverflow或任何地方找到任何地方。

请注意,在Heroku上部署了相同的代码,它与相同的数据库版本Mongo 3.0.7,我在本地以及2.2.3尝试的ruby版本2.0.0一起正常工作。当我通过网络运行霰弹枪和运行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'

我的Rspec代码:

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

代码实现是:

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为MongoDB提供了这个部分:

# MongoDB
...
gem 'mongoid', '~> 5.0'
gem 'bson_ext'
gem 'bson'

奇怪的是,我只在我的机器上出现此错误,并且刚刚开始。我正在使用OS X El Capitan。我可以从命令行访问mongodb集合而没有问题,可以运行相同的等效查询来获得我想要的结果:

> 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" } }

我尝试了其他集合,其他查询,其他变体,但仍然会遇到相同的错误。我恢复了github的旧代码,这个代码确实工作,但问题仍然存在,所以我很清楚我的代码或配置没有任何问题。我尝试了2.0.0 - 2.2.3的不同ruby版本,4 - 5的不同mongoid版本...再次相同版本的代码和安装在Heroku上工作正常,但不是我的机器:(

2 个答案:

答案 0 :(得分:0)

我不确定这是否是您问题的根源,但我在您的get_book_id类方法中看到了一些奇怪的事情。

首先,这永远不会离开book.nil?

book = where(:title => book_title.downcase.strip)

这会在[{1}}中留下Mongoid::Contextual,查询可能会或可能找不到任何内容,但book在任何一种情况下都不会book。这意味着你的:

nil
下一行

没有做任何有用的事情。这也意味着return unless book 可以book[0]在这里:

nil

当您通常拨打book[0]._id 时,您也会调用_id方法。

我认为你的方法会更好:

id

def self.get_book_id book_title book = find_by(:title => book_title.downcase.strip) return unless book book.id end 只是简短的说法find_by(query)所以where(query).first如果无法找到,book = find_by(...)nil book <{1}}中的任何内容和Bible::Book,如果能够找到某些内容的话。

如果您有ActiveSupport,您也可以说:

book

隐藏find_by(:title => book_title.downcase.strip).try(:id) 支票。您也可以通过nil调用只将only拉出MongoDB:

_id

答案 1 :(得分:0)

当为mongoid:uri: <%= ENV['MONGOLAB_URI'] %>

指定了错误的生产配置网址时,我遇到了类似的错误