problems with ActiveRecord::Associations:CollectionProxy

34 views
Skip to first unread message

Rose M Williams

unread,
Apr 14, 2021, 1:40:11 PM4/14/21
to rspec
ruby 2.6.6
rails 4.2.11
rspec-rails 3.7.2

I'm having trouble setting up a test on a SessionsController to show that after a User is created with omniauth, an authorization is then created that has all of its correct values. 

I hope I'm not giving too much context here, but if anyone is willing to look at this, I don't want to waste their time by not having all the context (and there is a lot of it!)

My students are learning Agile Development and are using Cucumber for their Acceptance testing and RSpec for their Unit testing.  Many of them are asking me about this or similar problems they are having with tests involving proxy objects created via associations, and I honestly don't have an answer for them.  I'm scouring all of my books and the internet to find a solution.

code in controller:
    user = User.create_with_omniauth(auth_hash['info'])
    auth = user.authorizations.create_with_omniauth(auth_hash)
    private
      def auth_hash
    # ensures availability but only retrieved once per cycle
    @auth_hash ||= request.env['omniauth.auth']
  end

schema:

ActiveRecord::Schema.define(version: 20210414024936) do
  create_table "authorizations", force: :cascade do |t|
    t.string   "provider"
    t.string   "uid"
    t.integer  "user_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  add_index "authorizations", ["user_id"], name: "index_authorizations_on_user_id"

  create_table "users", force: :cascade do |t|
    t.string   "name"
    t.string   "email"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end
end

code in models:

class User < ActiveRecord::Base
  has_many :authorizations
  validates :name, :email, :presence => true
  
  # save new user info
  def self.create_with_omniauth info
    create!(name: info['name'], email: info['email'])
  end
end

class Authorization < ActiveRecord::Base
  belongs_to :user
  validates :provider, :uid, :presence => true
  validates_uniqueness_of :uid, scope: :provider
    
  # create new authorization
  def self.create_with_omniauth auth
    create!(uid: auth['uid'], provider: auth['provider'])
  end
end

spec_helper.rb:
require 'omniauth'

OmniAuth.config.test_mode = true
omniauth_hash = { 'provider' => 'github',
                  'uid' => "12345",
                  'info' => {
                      'name' => "SUNY Tester",
                      'email' =>"ste...@binghamton.edu",
                  }
}
OmniAuth.config.add_mock(:github, omniauth_hash)

rails_helper.rb
Rails.application.env_config["omniauth.auth"] = OmniAuth.config.mock_auth[:github]   

sessions_controller_spec.rb:

require 'rails_helper'
RSpec.describe SessionsController, type: :controller do
  describe "GET #create" do
    context 'register with github' do
      describe 'When signing up for first time' do
        let(:user1) {instance_double('User', name: 'SUNY Tester', email: 'ste...@binghamton.edu')} 
        let(:authorization1) {instance_double('Authorization', provider: 'github', uid: '12345', user_id: '1')}   
        it "creates a User" do
          expect(User).to receive(:create_with_omniauth).with(OmniAuth.config.mock_auth[:github]['info']).and_return(user1)
          post :create, provider: :github  
        end

       # none of the following work, just a couple examples  of what I've tried 
        it "creates an Authorization" do
          #allow(user1).to receive(:authorizations.create_with_omniauth).with(OmniAuth.config.mock_auth[:github]['info']).and_return(user1)
         # expect(authorization1).to be_a_new(Authorization)
        #  expect(user1.authorizations).to receive(:create_with_omniauth).with(OmniAuth.config.mock_auth[:github]).and_return(authorization1)
          post :create, provider: :github
        end

The error messages are always something along the lines of:
SessionsController GET #create register with github When signing up for first time creates a User
     Failure/Error: user.authorizations.create_with_omniauth(auth_hash)
       #<InstanceDouble(User) (anonymous)> received unexpected message :authorizations with (no args)

If I try to create the authorization directly instead of with the proxy object, the user_id doesn't get set.

No matter how I go about it, I can't seem to find a way to mock a proxy object (the instance of user that is just created .authorizations )

Ironically, All my code as well as the students' code is working, but I can't seem to find a proper way to test it.



Phil Pirozhkov

unread,
Apr 14, 2021, 3:45:28 PM4/14/21
to Jack Royal-Gordon
Will

```
expect { post :create, provider: :github }
.to change { User.last }.to(having_attributes(name: ..., email: ...))
```
work for you?
> --
> You received this message because you are subscribed to the Google Groups "rspec" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to rspec+un...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/rspec/6cea440c-85b1-4aba-856c-3a518e421835n%40googlegroups.com.

Rose M Williams

unread,
Apr 14, 2021, 4:41:41 PM4/14/21
to rs...@googlegroups.com
That sounds promising!  I'll try it right after this class is over . . .
THANKS!

You received this message because you are subscribed to a topic in the Google Groups "rspec" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/rspec/H_ADLjDiV9I/unsubscribe.
To unsubscribe from this group and all its topics, send an email to rspec+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/rspec/CAAk5Ok_BwG20jHXoEixZWkEndgoPffaXfENoG2Dy7_xo5rogxg%40mail.gmail.com.


--
--

Rose Williams

Lecturer

Department of Computer Science

Binghamton University

-----------------------------------------------

We are what we think. 

All that we are arises with our thoughts. 

With our thoughts, we make the world.

 

Shakyamuni Buddha

Rose M Williams

unread,
Apr 14, 2021, 4:44:06 PM4/14/21
to rs...@googlegroups.com
Although it's Authorizations I'm having trouble with.  User is working fine, actually, but maybe this approach would work on authorizations also.

Rose M Williams

unread,
Apr 14, 2021, 9:16:58 PM4/14/21
to rspec
Still no joy, I've tried a number of solutions.  the best so far is resulting in what looks like a very silly and easy to fix error, but I haven't had any luck with it yet.  
Now I get the following error:
     Failure/Error: create!(uid: auth['uid'], provider: auth['provider'])
     
     ActiveRecord::RecordInvalid:
       Validation failed: Uid has already been taken

From the error message, it sounds like there is already a record in the database with I run the test, but when I look at it, it appears to be empty, so for the life of my I can't figure out where a duplicate uid is showing up.

Phil Pirozhkov

unread,
Apr 15, 2021, 4:41:39 AM4/15/21
to Jack Royal-Gordon
`puts caller_locations` in your `create_with_omniauth` should help to
pinpoint the problem.

Sanity check: you're cleaning up the DB between examples with
`use_transactional_fixtures!`, right?

On Thu, Apr 15, 2021 at 4:17 AM 'Rose M Williams' via rspec
> To view this discussion on the web visit https://groups.google.com/d/msgid/rspec/84c65fd4-81f6-4701-93bf-f64b02541f3fn%40googlegroups.com.

Rose M Williams

unread,
Apr 15, 2021, 6:08:42 PM4/15/21
to rspec
I am still not seeing where this problem is coming from.  I've configure the db strategy to be using transactions, via a block in my spec_helper.rb.  Your statement looks somewhat different.  Where would I put it?

Rose M Williams

unread,
Apr 16, 2021, 2:10:48 AM4/16/21
to rspec
Thanks so much, Phil, for your help!

I've been using the default setting for database_cleaner 1.4.1
I was reading that the newer versions are more specific, so I tried using the 'database_cleaner-active_record gem', and configuring as suggested.
Surprisingly, the previously failing tests are now passing without any issue.  Thanks again for pointing me in the right direction.

Reply all
Reply to author
Forward
0 new messages