Question

Next line:

  User.find(session[:user_id])

in which session[:user_id] previously defined:

  session[:user_id] = user.id

In spec works fine and returns user model, but in real app (development mode) it fails:

MOPED: 127.0.0.1:27017 QUERY        database=rails_api_development collection=users selector={"_id"=>{"$oid"=>BSON::ObjectId('533c3958616c641142010000')}} flags=[] limit=0 skip=0 batch_size=nil fields=nil runtime: 1.0680ms
Completed 500 Internal Server Error in 15ms

Moped::Errors::QueryFailure - The operation: #<Moped::Protocol::Query
    @length=89
@request_id=2
@response_to=0
@op_code=2004
@flags=[]
@full_collection_name="rails_api_development.users"
@skip=0
@limit=0
@selector={"_id"=>{"$oid"=>BSON::ObjectId('533c3958616c641142010000')}}
@fields=nil>
    failed with error 10068: "invalid operator: $oid"

See https://github.com/mongodb/mongo/blob/master/docs/errors.md
for details about this error.:
  moped (2.0.0.rc1) lib/moped/operation/read.rb:50:in `block in execute'
  moped (2.0.0.rc1) lib/moped/node.rb:594:in `block (2 levels) in flush'

full log

App works when i change find to:

  User.find(session[:user_id]['$oid'])

But spec fails with:

   1) ApplicationController current_user when current_user is nil and user_id stores in session finds and returns it from db
 Failure/Error: expect(subject.send(:current_user)).to eq user
 NoMethodError:
   undefined method `[]' for BSON::ObjectId('533fae9e616c6464a4010000'):BSON::ObjectId
 # ./app/controllers/application_controller.rb:7:in `current_user'
 # ./spec/controllers/application_controller_spec.rb:22:in `block (5 levels) in <top (required)>'

In spec i'm working with real db, with database_cleaner. so, i guess all the same (but obviously not)

My gemfile

I've tried to make to_s, to_json for user_id according to this, add mongoid initialize file with this, also tried to cahnge multi_json moped versions - didn't help.

I have application controller with spec there

I barely hope someone can help, taking into account the results of previous such tricky questions, but anyway, thanks in advance!

UPDATE: failing test:

context "when current_user is nil" do
  context "and user_id stores in session" do
    let(:user) { create(:user) }
    before { allow(subject).to receive(:session).and_return({ user_id: user.id }) }
    before { allow(User).to receive(:find).and_return(user) }

    it "finds and returns it from db" do
      expect(User).to receive(:find)
>     expect(subject.send(:current_user)).to eq user
    end
  end
Was it helpful?

Solution

I had a similar problem earlier, the problem was the json representation of BSON::ObjectId in session. As you also found, calling to_s solved this problem for me. You need to make sure that session contains the id in string format. So whenever you assign the user id to session, call to_s. Try to make the following changes:

Change current_user= in ApplicationController to:

def current_user=(user)
  @current_user = user
  session[:user_id] = user.try(:id).try(:to_s)
end

Change spec to:

context "and user_id stores in session" do
  let(:user) { create(:user) }
  before { allow(subject).to receive(:session).and_return({ user_id: user.id.to_s }) }
  before { allow(User).to receive(:find).and_return(user) }

  it "finds and returns it from db" do
    expect(User).to receive(:find)
    expect(subject.send(:current_user)).to eq user
  end
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top