具有Mongoid :: Errors :: DocumentNotFound异常的Mongoid动态查找程序引发

时间:2011-07-12 09:11:54

标签: ruby-on-rails-3 mongoid

我正在为使用Mongoid的这个项目构建一个REST api。

我已设置以下内容以捕获Mongoid::Errors::DocumentNotFound例外:

rescue_from Mongoid::Errors::DocumentNotFound in my base controller

在我的控制器中,我有这个查询代码:

@current_account.users.find(:first, :conditions => {:name => "some_name"})

上述查询只返回nil。它不会引发异常。 尝试了另一种语法:

User.find(:conditions => {:name => "same"}).first

所有这些方法都在内部运行where而afaik where不会引发异常,它只返回[]

那么解决这个问题的方法是什么?我想要部分动态查找器但是也应该引发异常吗?

2 个答案:

答案 0 :(得分:6)

我今天遇到了同样的问题,并找到了另一种解决方案。

raise_not_found_error设为false。所以你的config / mongoid.yml应该是

development:
  host: localhost
  port: 10045
  username: ...
  password: ...
  database: ...
  raise_not_found_error: false

来自http://mongoid.org/docs/installation/configuration.html

答案 1 :(得分:3)

我相信Mongoid只会在使用DocumentNotFound方法时通过传入对象的id(而不是条件)来引发find异常。否则它将返回零。来自Mongoid来源:

# lib/mongoid/errors/document_not_found.rb

# Raised when querying the database for a document by a specific id which
# does not exist. If multiple ids were passed then it will display all of
# those.

您必须手动检查以查看是否有任何结果,并自行提升DocumentNotFound异常(不是很好),或者提出自己的自定义异常(更好的解决方案)。

前者的例子是这样的:

raise Mongoid::Errors::DocumentNotFound.new(User, params[:name]) unless @current_account.users.first(:conditions => {:name => params[:name]})

更新:我还没有对此进行测试,但应该允许您拨打电话(或者至少指向正确的方向 - 我希望!):

@current_account.users.where!(:conditions => {:name => params[:name]})

如果从查询返回的集合为空,则会抛出自定义Mongoid::CollectionEmpty错误。请注意,它不是最有效的解决方案,因为为了查明返回的集合是否为空 - 它必须实际处理查询。

然后您需要做的就是从Mongoid::CollectionEmpty进行救援(或者也可以)。

# lib/mongoid_criterion_with_errors.rb
module Mongoid
  module Criterion
    module WithErrors
      extend ActiveSupport::Concern

      module ClassMethods
        def where!(*args)
          criteria = self.where(args)
          raise Mongoid::EmptyCollection(criteria) if criteria.empty?
          criteria
        end
      end
    end
  end

  class EmptyCollection < StandardError
    def initialize(criteria)
      @class_name = criteria.class
      @selector = criteria.selector
    end

    def to_s
      "Empty collection found for #{@class_name}, using selector: #{@selector}"
    end
  end
end

# config/application.rb
module ApplicationName
  class Application < Rails::Application
    require 'mongoid_criterion_with_errors'
    #...snip...
  end
end

# app/models/user.rb
class User
  include Mongoid::Document
  include Mongoid::Timestamps
  include Mongoid::Criterion::WithErrors
  #...snip...
end