Devise 1.5 + Omniauth 1.0 + Facebook: undefined method `extra`

家住魔仙堡 提交于 2019-12-11 03:17:56

问题


I'm trying to get my Cucumber test to work with Devise 1.5 and Omniauth 1.0, with Facebook authentication. Funny thing is, it works on development mode, but when run the Cukes test, it fails with this message:

undefined method `extra' for #<Hash:0x007f95f0d26260> (NoMethodError)
./app/models/user.rb:13:in `find_for_facebook_oauth'
./app/controllers/users/omniauth_callbacks_controller.rb:4:in `facebook'
(eval):2:in `click_link'
./features/step_definitions/web_steps.rb:58:in `/^(?:|I )follow "([^"]*)"$/'
features/facebook_auth.feature:11:in `When I follow "Sign in with Facebook"'

Here is the corresponding method:

def self.find_for_facebook_oauth(access_token, signed_in_resource=nil)

    data = access_token.extra.raw_info
    if user = User.where(:email => data.email).first
        user
    else 
        User.create!(:email => data.email, :password => Devise.friendly_token[0,20]) 
    end
end

To get the Cukes test to be all green, I had to do this workaround, which then breaks the Development mode code. So for now, I'm doing this:

    case Rails.env
    when "test"
        data = access_token['extra']['user_hash']
        if user = User.find_by_email(data["email"])
            user
        else 
            User.create!(:email => data["email"], :password => Devise.friendly_token[0,20])
        end
    else
        data = access_token.extra.raw_info
        if user = User.where(:email => data.email).first
            user
        else 
            User.create!(:email => data.email, :password => Devise.friendly_token[0,20]) 
        end
    end     

Seems like the offending line is data = access_token.extra.raw_info.

The way I'm mocking the Facebook hash is:

OmniAuth.config.add_mock(:facebook, {
    :uid => '12345',
    :nickname => 'zapnap',
    :extra => {
      :user_hash => {
        'email' => 'someone@webs.com'
      }
    }
  })

And I have turned on OmniAuth.config.test_mode = true by appending it at the last line of test.rb.

Any ideas would be greatly appreciated!


回答1:


I got exactly the same error and could somehow get it to be all green. Although I use stub instead of mock as is written here, hope it can be a help.

As it is discussed here, this occurs because OmniAuth1.0 uses Hashie::Mash for the part we got error. So, we figured out to use a Hashie::Mash object to return instead of a Hash. In order to do so,

I added this to spec_helper..

require "omniauth"

and modified stub method like this..

def stub_env_for_omniauth
  request.env["devise.mapping"] = Devise.mappings[:user]
  pre = { "omniauth.auth" => { "provider" => "facebook", "uid" => "1234", "credentials" => {"token" => "abcdefg"}, "extra"=>{"raw_info" => {"id" => "1234567", "email" => "ghost@nobody.com", "name" => "Mark", "gender" => "male" }}}}
  env = OmniAuth::AuthHash.new(pre)
  @controller.stub!(:env).and_return(env)
end

This works for me.




回答2:


You can place settings in the spec_helper.rb, as alternative to stub_env_for_omniauth method.

  OmniAuth.config.test_mode = true
  OmniAuth.config.full_host = 'http://example.com'

  omni_hash = {
    'uid' => '12345',
    'provider' => 'facebook',
    "info" => {
      "email" => Faker::Internet.email,
      "image" => "http://example.com/pic.img"
     },
    "extra" => {
      "raw_info" => {
        "first_name" => Faker::Name.first_name,
        "last_name" => Faker::Name.last_name,
        "name" => Faker::Internet.user_name,
        "gender" => "male",
        "locale" => "en"
      }
    }
  }
  OmniAuth.config.mock_auth[:facebook] = OmniAuth::AuthHash.new(omni_hash)



回答3:


For Cucumber tests an additional mock object seems to work:

Given /^a new facebook user "([^"]*)"$/ do |name|
  OmniAuth.config.test_mode = true
  OmniAuth.config.mock_auth[:facebook] = {
    :provider => 'facebook',
    :uid => '123545',
    :name => name}

  m = mock("mock_extra",
    :raw_info => 
      mock("mock_raw_info", 
        :email => 'someone@webs.com',
        :first_name => name,
        :last_name => "xyz"))

  OmniAuth.config.mock_auth[:facebook].stub(:extra).and_return(m)        
end


来源:https://stackoverflow.com/questions/8556439/devise-1-5-omniauth-1-0-facebook-undefined-method-extra

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!