How can I test omniauth-facebook in rails 5 with minitest - ruby

I read previous possible questions that may have the answer but that not what I asked for.
First of all I am start to use test. However I already successful setup Omniauth-facebook for my App but still like to go back and test.
-sessions_controller.rb
class SessionsController < ApplicationController
def new
#title= 'Sign In'
end
def create
auth = request.env["omniauth.auth"]
user = User.from_omniauth(auth)
session[:user_id] = user.id
if params.permit[:remember_me]
cookies.permanent[:auth_token] = user.auth_token
else
cookies[:auth_token] = user.auth_token
end
refresh_to root_path, :ma_notice => "Logged in"
rescue
redirect_to root_path, :alert=> "Authentication failed, please try again."
end
def destroy
#session[:user_id] = nil
cookies.delete(:auth_token)
refresh_to root_path, :ma_notice => "Logged Out"
end
def failure
ma_log "Authentication failed, please try again."
redirect_to root_path, :alert=> "Authentication failed, please try again."
end
end
-app/models/user.rb
class User
....
....
def self.from_omniauth(auth)
where(auth.slice(:uid, :provider, :email)).first_or_create do |user|
case auth.provider
when 'identity'
identity = Identity.find auth.uid
user.code = identity.code
user.email = identity.email
else
user.email = auth.info.email
user.uid = auth.uid
user.provider = auth.provider
user.code = auth.info.name
user.role = "M"
end
end
end
def send_password_reset
generate_token(:password_reset_token)
self.password_reset_sent_at = Time.zone.now
save!
UserMailer.password_reset(self).deliver
end
So what I did
Test routes (Its seem simple but sometime I might forgot because I changing from dynamic route to fixed route as required in rails 5.2)
-test/integration/authen_test.rb
require 'test_helper'
class RoutesTest < ActionController::TestCase
test 'facebook login' do
assert_routing '/auth/facebook/callback', {controller: 'sessions', action: 'create',provider: 'facebook'}
end
test 'facebook login post' do
assert_routing({path: '/auth/facebook/callback', method: 'post'},{controller: 'sessions', action: 'create' ,provider: 'facebook'})
end
end
I want to test if facebook accept login and return call back.
-test/models/user_test.rb
require 'test_helper'
class UserTest < ActiveSupport::TestCase
test "Facebook validation" do
auth = {provider: :facebook, FACEBOOK_API: "111111111111111", FACEBOOK_KEY: "11111111111111111111111111111111"}
user = User.from_omniauth(auth)
puts user
assert_not nil
end
end
Problem: It's always green even change FACEBOOK_API. I found the user from puts as well. It's seem like user.from _omniauth already gone to facebook and get info using FACEBOOK_API from .env not one I provided. Then how I can test if it really connected with facebook.
The same with this related test. It's always green in any FACEBOOI_API. That won't work as well.
View Test. I like to test if no facebook login the system or not. The login would display accordingly. Still have no idea as stuck with Q.2 perhap someone could share how you do the test.
To Setup Integration Testing-Omniauth as documented
You can turn on "test mode" for OmniAuth like so:
OmniAuth.config.test_mode = true Once you have enabled test mode, all
requests to OmniAuth will be short circuited to use the mock
authentication hash as described below. A request to /auth/provider
will redirect immediately to /auth/provider/callback.
Then said
OmniAuth.config.add_mock(:twitter, {:uid => '12345'})
OK but where to put that code to turn on
so I assumed the only one is
-config/initializer/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
provider :identity,
:fields => [:code, :email],
:on_failed_registration=> lambda { |env|
IdentitiesController.action(:new).call(env)
}
provider :facebook, ENV['FACEBOOK_API'], ENV['FACEBOOK_KEY']
OmniAuth.config.test_mode = true
OmniAuth.config.mock_auth[:facebook] = :invalid_credentials
end
Here I used test from related question but used my method :create.
It didn't do anything than green, even changed .test_mode = false
-test/integration/sessions_controller_test.rb
require 'test_helper'
class SessionsControllerTest < ActionController::TestCase
test '#signup_success' do
OmniAuth.config.test_mode = true
OmniAuth.config.mock_auth[:facebook] = OmniAuth::AuthHash.new({
'provider' => 'facebook',
'uid' => '123451234512345',
'info' => {'email' => 'testuser#testmail.com', 'name' => 'test', 'image' => ''}
})
request.env['omniauth.env'] = OmniAuth.config.mock_auth[:facebook]
get :create
end
end

You can use omniauth test helpers. Here is the link:
https://github.com/omniauth/omniauth/wiki/Integration-Testing
Setup Mock Auth:
OmniAuth.config.mock_auth[:facebook] = OmniAuth::AuthHash.new({
:provider => 'facebook',
:uid => '123545'
# etc.
})

What i did and what worked for me was setting up mocks in my spec_helper file for various scenarios.
OmniAuth.config.test_mode = true
omniauth_hash = { 'provider' => 'twitter',
'uid' => '12345',
'info' => {
'name' => 'test',
'email' => 'test#test.com',
'nickname' => 'testnick'
},
'extra' => {
'raw_info' =>
{
'location' => 'Coralvilleo'
}
}
}
omniauth_hash_fb = { 'provider' => 'facebook',
'uid' => '12345',
'info' => {
'name' => 'test',
'email' => 'test#testsomething.com'
},
'extra' => {'raw_info' =>
{ 'location' => 'Chicago'
}
}
}
omniauth_hash_fail = { 'provider' => 'facebook',
'uid' => '12345',
'info' => {
},
'extra' => {'raw_info' =>
{ 'location' => 'Chicago'
}
}
}
omniauth_hash_fail_2 = { 'provider' => 'facebook',
'uid' => '12345',
'info' => {
},
'extra' => {'raw_info' =>
{ 'location' => 'Chicago'
}
}
}
omniauth_hash_fail_complete = { 'provider' => 'twitter'}
OmniAuth.config.add_mock(:twitter, omniauth_hash)
OmniAuth.config.add_mock(:facebook, omniauth_hash_fb)
OmniAuth.config.add_mock(:facebook_fail, omniauth_hash_fail)
OmniAuth.config.add_mock(:twitter_fail, omniauth_hash_fail_2)
Then using these methods in my rspec tests for controller like so.
it 'should successfully create a user with twitter' do
request.env['omniauth.auth'] = OmniAuth.config.mock_auth[:twitter]
expect {
post :twitter, provider: :twitter
}.to change{ User.count }.by(1)
end
it 'should redirect the user to the root url with twitter' do
request.env['omniauth.auth'] = OmniAuth.config.mock_auth[:twitter]
post :twitter, provider: :twitter
response.should redirect_to root_path
end
name of the mocks to be specified and linked to what we specified in the helper.
OmniAuth.config.mock_auth[name of the mock you specified in spec helper].

Related

How to insert video youtube api v3 through service account with ruby

My goal is to let users of my app upload to my youtube account through my server.
I have a developer acount, with youtube data api enabled and a service account client setup and for some reason I am not authorized. I dug through the net to try and figure out why and found many things.
I tried giving permissions in the admin security settings with the projects client id and scope.
Many people were saying that this error is caused because I don't have a youtube account associated with my account. but I have no idea how to associate these.
This is my upload_video.rb script:
require 'rubygems'
require 'google/api_client'
require 'google/api_client/client_secrets'
require 'google/api_client/auth/file_storage'
require 'google/api_client/auth/installed_app'
require 'certified'
DEVELOPER_KEY = "MY-DEVELOPER-KEY"
YOUTUBE_UPLOAD_SCOPE = 'https://www.googleapis.com/auth/youtube.upload'
YOUTUBE_API_SERVICE_NAME = 'youtube'
YOUTUBE_API_VERSION = 'v3'
def get_authenticated_service
puts #PROGRAM_NAME
client = Google::APIClient.new(
:application_name => $PROGRAM_NAME,
:application_version => '1.0.0'
)
key = Google::APIClient::KeyUtils.load_from_pkcs12('oauth2service.p12', 'notasecret')
auth_client = Signet::OAuth2::Client.new(
:token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
:audience => 'https://accounts.google.com/o/oauth2/token',
:scope => YOUTUBE_UPLOAD_SCOPE,
:issuer => 'SERVICE ACCOUNT EMAIL ADDRESS',
:signing_key => key)
auth_client.fetch_access_token!
client.authorization = auth_client
youtube = client.discovered_api(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION)
return client, youtube
end
def upload2youtube file, title, description, category_id, keywords, privacy_status
client, youtube = get_authenticated_service
begin
body = {
:snippet => {
:title => title,
:description => description,
:tags => keywords.split(','),
:categoryId => category_id,
},
:status => {
:privacyStatus => privacy_status
}
}
videos_insert_response = client.execute!(
:api_method => youtube.videos.insert,
:body_object => body,
:media => Google::APIClient::UploadIO.new(file, 'video/*'),
:parameters => {
:uploadType => 'resumable',
:part => body.keys.join(',')
}
)
videos_insert_response.resumable_upload.send_all(client)
puts "Video id '#{videos_insert_response.data.id}' was successfully uploaded."
rescue Google::APIClient::TransmissionError => e
puts e.result.body
end
end
This is how I am running it from another script:
require 'google/api_client'
require_relative 'upload_video'
$PROGRAM_NAME = 'MY-PROJECT-NAME'
upload2youtube File.open("somevideo.avi"), "title", "description", 'categoryid', 'tag1,tag2,tag3', 'unlisted'
And this is the result:
{
"error": {
"errors": [
{
"domain": "youtube.header",
"reason": "youtubeSignupRequired",
"message": "Unauthorized",
"locationType": "header",
"location": "Authorization"
}
],
"code": 401,
"message": "Unauthorized"
}
}
What am I doing wrong
#!/usr/bin/ruby
require 'rubygems'
require 'google/api_client'
require 'google/api_client/client_secrets'
require 'google/api_client/auth/file_storage'
require 'google/api_client/auth/installed_app'
require 'certified'
class Youtube_Helper
##client_email = '' #email id from service account (that really long email address...)
##youtube_email = '' #email associated with youtube account
##p12_file_path = '' #path to the file downloaded from the service account (Generate new p12 key button)
##p12_password = '' # password to the file usually 'notasecret'
##api_key = nil # The API key for non authenticated things like lists
YOUTUBE_UPLOAD_SCOPE = 'https://www.googleapis.com/auth/youtube.upload'
YOUTUBE_API_SERVICE_NAME = 'youtube'
YOUTUBE_API_VERSION = 'v3'
##client = nil
##youtube = nil
FILE_POSTFIX = '-oauth2.json'
def initialize(client_email, youtube_email, p12_file_path, p12_password, api_key)
##client_email=client_email
##youtube_email=youtube_email
##p12_file_path=p12_file_path
##p12_password=p12_password
##api_key = api_key
end
def get_authenticated_service
credentialsFile = $0 + FILE_POSTFIX
needtoauthenticate = false
#api_client = Google::APIClient.new(
:application_name => $PROGRAM_NAME,
:application_version => '1.0.0'
)
key = Google::APIClient::KeyUtils.load_from_pkcs12(##p12_file_path, ##p12_password)
#auth_client = Signet::OAuth2::Client.new(
:token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
:audience => 'https://accounts.google.com/o/oauth2/token',
:scope => YOUTUBE_UPLOAD_SCOPE,
:issuer => ##client_email,
:person => ##youtube_email,
:signing_key => key)
if File.exist? credentialsFile
puts 'credential file exists'
puts credentialsFile.to_s
File.open(credentialsFile, 'r') do |file|
credentials = JSON.load(file)
if !credentials.nil?
puts 'get credentials from file'
#auth_client.access_token = credentials['access_token']
#auth_client.client_id = credentials['client_id']
#auth_client.client_secret = credentials['client_secret']
#auth_client.refresh_token = credentials['refresh_token']
#auth_client.expires_in = (Time.parse(credentials['token_expiry']) - Time.now).ceil
#api_client.authorization = #auth_client
if #auth_client.expired?
puts 'authorization expired'
needtoauthenticate = true
end
else
needtoauthenticate = true
end
end
else
needtoauthenticate = true
end
if needtoauthenticate
#auth_client.fetch_access_token!
#api_client.authorization = #auth_client
save(credentialsFile)
end
youtube = #api_client.discovered_api(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION)
##client = #api_client
##youtube = youtube
return #api_client, youtube
end
def save(credentialsFile)
File.open(credentialsFile, 'w', 0600) do |file|
json = JSON.dump({
:access_token => #auth_client.access_token,
:client_id => #auth_client.client_id,
:client_secret => #auth_client.client_secret,
:refresh_token => #auth_client.refresh_token,
:token_expiry => #auth_client.expires_at
})
file.write(json)
end
end
def upload2youtube file, title, description, category_id, keywords, privacy_status
puts 'begin'
begin
body = {
:snippet => {
:title => title,
:description => description,
:tags => keywords.split(','),
:categoryId => category_id,
},
:status => {
:privacyStatus => privacy_status
}
}
puts body.keys.join(',')
# Call the API's videos.insert method to create and upload the video.
videos_insert_response = ##client.execute!(
:api_method => ##youtube.videos.insert,
:body_object => body,
:media => Google::APIClient::UploadIO.new(file, 'video/*'),
:parameters => {
'uploadType' => 'multipart',
:part => body.keys.join(',')
}
)
puts'inserted'
puts "'#{videos_insert_response.data.snippet.title}' (video id: #{videos_insert_response.data.id}) was successfully uploaded."
rescue Google::APIClient::TransmissionError => e
puts e.result.body
end
return videos_insert_response.data.id #video id
end
def upload_thumbnail video_id, thumbnail_file, thumbnail_size
puts 'uploading thumbnail'
begin
thumbnail_upload_response = ##client.execute({ :api_method => ##youtube.thumbnails.set,
:parameters => { :videoId => video_id,
'uploadType' => 'media',
:onBehalfOfContentOwner => ##youtube_email},
:media => thumbnail_file,
:headers => { 'Content-Length' => thumbnail_size.to_s,
'Content-Type' => 'image/jpg' }
})
rescue Google::APIClient::TransmissionError => e
puts e.result.body
end
end
def get_video_statistics video_id
client = Google::APIClient.new(:key => ##api_key,
:application_name => $PROGRAM_NAME,
:application_version => '1.0.0',
:authorization => nil)
youtube = client.discovered_api(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION)
stats_response = client.execute!( :api_method => youtube.videos.list,
:parameters => {:part => 'statistics', :id => video_id }
)
return stats_response
end
end

Integrating Google+ into Rails app (execute not working)

I am trying to display data from Google+ by adapting this to rails https://github.com/google/google-api-ruby-client I created a rails app, made a few tweaks to get oauth working with the client_secret.json, but when the request executes, nothing displays.
welcome_controller:
class WelcomeController < ApplicationController
def index
require 'google/api_client'
require 'google/api_client/client_secrets'
require 'google/api_client/auth/installed_app'
$credentials = Google::APIClient::ClientSecrets.load
# Initialize the client.
$authorization = Signet::OAuth2::Client.new(
:authorization_uri => $credentials.authorization_uri,
:token_credential_uri => $credentials.token_credential_uri,
:client_id => $credentials.client_id,
:client_secret => $credentials.client_secret,
:redirect_uri => $credentials.redirect_uris.first,
:scope => 'https://www.googleapis.com/auth/plus.login')
#client = Google::APIClient.new(
:application_name => 'X',
:application_version => 'X'
)
# Initialize Google+ API. Note this will make a request to the
# discovery service every time, so be sure to use serialization
# in your production code. Check the samples for more details.
#plus = #client.discovered_api( "plus", "v1" )
# Make an API call.
#google_plus_info = #client.execute(
:api_method => #plus.activities.list,
:parameters => {'collection' => 'public', 'userId' => 'my_num_here'}
)
#puts #google_plus_info.data #tried this
render plain: "test: #{#google_plus_info.data}" #tried this too, just returns the call name
end
end
Anyone know why I'm getting it in this case, according to the API (i thought) this was a public call? NOTE: I changed this post in response to suggestions to show my current state of work.
Try replacing $authorization.execute with plus.execute
Take a look at https://github.com/google/google-api-ruby-client-samples/tree/master/googleplus
Here's a snippet from my working code:
#client = Google::APIClient.new(
:application_name => 'X',
:application_version => 'X'
)
#client.authorization.update_token!(:access_token => 'X', :refresh_token => 'X')
#plus = #client.discovered_api( "plus", "v1" )
#google_plus_info = #client.execute(
:api_method => #plus.people.get,
:parameters => {'collection' => 'public', 'userId' => 'me'}
)

Oauth2 error with MapMyFitness API

I'm trying to use the MapMyFitness API (www.mapmyapi.com) with Ruby on Rails 3.2 and the oauth2 gem. First, my app generates the auth_url in "get_auth_url". The browser then navigates to it and a callback is returned to "mapmyfitness_callback" once authenticated. The "mapmyfitness_callback" also gets the list of "workouts" and those are displayed in the browser.
The problem is when the user selects a workout to download. To retrieve the selected workout, I call "get_workout". However, I'm having difficulties getting the appropriate token for the request.
The line below crashes:
workout_data = access_token.get('/v7.0/workout/' + workout_id, :params => { 'field_set' => 'time_series' }, :headers => {'Api-Key' => ENV['MMF_API_KEY'], 'Authorization' => auth_token}).body
with: OAuth2::Error (:
{"oauth1_error":"Malformed authorization header","oauth1_error_code":"OAUTH1:UNKNOWN"}):
app/controllers/telemetry_controller.rb:60:in `get_workout'
The entire controller code:
require 'oauth2'
class TelemetryController < ApplicationController
def get_auth_url
auth_url = mmf_client.auth_code.authorize_url(:redirect_uri => 'http://localhost:3000/telemetry/mapmyfitness_callback')
respond_to do |format|
format.json{ render :json => {:auth_url => auth_url}.to_json }
end
end
def mapmyfitness_callback
# Get user
#code = params[:code]
token = mmf_client.auth_code.get_token(#code, :redirect_uri => 'http://localhost:3000/telemetry/mapmyfitness_callback', :headers => {'Api-Key' => ENV['MMF_API_KEY']})
mmf_user = JSON.parse(token.get('/v7.0/user/self', :headers => {'Api-Key' => ENV['MMF_API_KEY'], 'Authorization' => #code}).body)
mmf_user_id = mmf_user['id']
#auth_token = token.token
# Get workouts
mmf_workouts = JSON.parse(token.get('/v7.0/workout', :params => { 'user' => mmf_user_id }, :headers => {'Api-Key' => ENV['MMF_API_KEY'], 'Authorization' => #code}).body)
#workout_list = Array.new
mmf_workouts['_embedded']['workouts'].each do |workout|
workout_data = {:name => workout['name'],
:id => workout['_links']['self'][0]['id']}
#workout_list.push(workout_data)
end
render :layout => false
end
def get_workout
code = params[:code]
auth_token = params[:auth_token]
access_token = OAuth2::AccessToken.new(mmf_client, auth_token, {
:mode => :query,
:param_name => "oauth2_access_token",
})
puts access_token.to_yaml
# Get workout
workout_id = params[:workout_id]
workout_data = access_token.get('/v7.0/workout/' + workout_id, :params => { 'field_set' => 'time_series' }, :headers => {'Api-Key' => ENV['MMF_API_KEY'], 'Authorization' => auth_token}).body
respond_to do |format|
format.json{ render :json => {:mmf_workout_data => workout_data}.to_json }
end
end
private
def mmf_client
client = OAuth2::Client.new(
ENV['MMF_API_KEY'],
ENV['MMF_SECRET_KEY'],
:authorize_url => "https://www.mapmyfitness.com/v7.0/oauth2/authorize/",
:token_url => "https://oauth2-api.mapmyapi.com/v7.0/oauth2/access_token/",
:site => "https://oauth2-api.mapmyapi.com"
)
end
end
I figured it out. get_workout needs to be like this:
def get_workout
auth_token = params[:auth_token]
token = OAuth2::AccessToken.new(mmf_client, auth_token)
# Get workout
workout_id = params[:workout_id]
workout_data = token.get('/v7.0/workout/' + workout_id, :params => { 'field_set' => 'time_series' }, :headers => {'Api-Key' => ENV['MMF_API_KEY'], 'Authorization' => auth_token}).body
respond_to do |format|
format.json{ render :json => {:mmf_workout_data => workout_data}.to_json }
end
end
The problem with your call to AccessToken.new is the "param_name".
from the docs (http://www.rubydoc.info/github/intridea/oauth2/ebe4be038ec14b349682/OAuth2/AccessToken)
:param_name (String) — default: 'bearer_token' — the parameter name to use for transmission of the Access Token value in :body or :query transmission mode
The default value is "bearer_token", as it should be, but, here, you were changing it to "oauth2_access_token".

JIRA + Savon + Ruby issues

I am trying to get my new application integrated with JIRA for management of our customer's support tickets. What I had envisioned the system doing was in a before_filter gathering a user's account from within JIRA - from that I can pull up a list of accounts and what not, and if they don't have one then we create one based on their details in the Rails application. Thing is I'm having major issues doing things like removing the user from the jira-users group and adding them to a separate group I have for customers called customer-support. This is the code I have currently:
def current_jira_user
# Fetch the current user in JIRA, if we don't exist, create it!
user_try = #jira.request :get_user do |soap|
soap.body = { :token => #token, :username => "#{current_user.username}" }
end
if user_try.to_hash[:get_user_response][:get_user_return][:href].nil?
# We need to create the user
#jira.request :create_user do |soap|
soap.body = {
:token => #token,
:username => "#{current_user.username}",
:password => UUID.new.to_s,
:fullName => current_user.full_name,
:email => "noreply#XXXXX.XXX" #this is such a hack to get around JIRA's "you've got an account" email
}
end
new_user = RemoteUser.find(current_user.username)
#jira.request :remove_user_from_group do |soap|
soap.body = { :token => #token, :group => RemoteGroup.find('jira-users'), :ruser => new_user }
end
#jira.request :add_user_to_group do |soap|
soap.body = { :token => #token, :group => RemoteGroup.find('customer-support'), :ruser => new_user }
end
new_user[:email] = current_user.email
#jira.request :update_user do |soap| # change their email to the valid one
soap.body = { :token => #token, :ruser => new_user }
end
new_user
else
user_try.to_hash[:get_user_response][:get_user_return]
end
end
def verify_jira_connection
# Verify that we can reach the JIRA instance
#jira = Savon::Client.new do
wsdl.document = JIRA_SOAP_URI
end
#jira.http.read_timeout = 300
#jira.http.auth.ssl.verify_mode = :none
#auth = #jira.request :login do |soap|
soap.body = { :username => JIRA_LOGIN, :password => JIRA_PASSWORD }
end
#token = #auth.to_hash[:login_response][:login_return]
end
## REMOTE CLASSES
class RemoteUser
include Savon::Model
client do
http.headers["Pragma"] = "no-cache"
http.auth.ssl.verify_mode = :none
end
namespace "http://beans.soap.rpc.jira.atlassian.com"
endpoint JIRA_SOAP_URI
basic_auth JIRA_LOGIN, JIRA_PASSWORD
actions :get_user
def self.find(username)
get_user(:username => username).to_hash
end
end
class RemoteGroup
include Savon::Model
client do
http.headers["Pragma"] = "no-cache"
http.auth.ssl.verify_mode = :none
end
namespace "http://beans.soap.rpc.jira.atlassian.com"
endpoint JIRA_SOAP_URI
basic_auth JIRA_LOGIN, JIRA_PASSWORD
actions :get_group
def self.find(group)
get_group(:groupName => group).to_hash
end
end
Users are created just fine, but when I get to the removeUserFromGroup call, I get (soapenv:Server.userException) com.atlassian.jira.rpc.exception.RemoteValidationException: group name cannot be null, needs a value. Using the Jira4R gem is out thanks to our using Ruby 1.9.2. Any help is appreciated. Thanks!
Maybe you need to explicitly send the name?
:group => RemoteGroup.find('jira-users').name
instead of this
:group => RemoteGroup.find('jira-users')
If you were willing to do some rewriting, you could try using a Ruby 1.9-compatible fork of jira4r

OmniAuth Facebook Authentication Nickname returning "profile.php?id=.."

I'm using Sinatra and OmniAuth, trying to authenticate using Facebook. Everything seems to be working properly except for the nickname property. My auth hash is returning something for the nickname, but it is not the person's nickname. For what I'm trying to do, getting the person's nickname is very important. And I already checked my Facebook page to make sure that I have a nickname set, and I do. It should be returning "HeroicEric".
get '/auth/:name/callback' do
auth = request.env["omniauth.auth"]
user = User.first_or_create({ :uid => auth["uid"]}, {
:uid => auth["uid"],
:username => auth["user_info"]["nickname"],
:name => auth["user_info"]["name"],
:email => auth["user_info"]["email"]
})
session[:user_id] = user.id
redirect '/user/' + user.id.to_s
end
The hash that is being returned looks like this:
"user_info"=>{
"name"=>"Eric Kelly",
"urls"=>
{
"Facebook"=>"http://www.facebook.com/profile.php?id=550432081",
"Website"=>nil
},
"nickname"=>"profile.php?id=550432081",
"last_name"=>"Kelly",
"image"=>"http://graph.facebook.com/550432081/picture?type=square",
"first_name"=>"Eric",
"email"=>"heroiceric#gmail.com"
},
The code extracting data from facebook OAuth answer is in oa-oauth-0.2.3/lib/omniauth/strategies/facebook.rb
def user_info
{
'nickname' => user_data["link"].split('/').last,
'email' => (user_data["email"] if user_data["email"]),
'first_name' => user_data["first_name"],
'last_name' => user_data["last_name"],
'name' => "#{user_data['first_name']} #{user_data['last_name']}",
'image' => "http://graph.facebook.com/#{user_data['id']}/picture?type=square",
'urls' => {
'Facebook' => user_data["link"],
'Website' => user_data["website"],
}
}
end
As you see, nickname is just a rigth part of URL. I suggest fixing facebook adapter to get an actual nickname. Facebook returns user_data filled with
{ ... "name"=>"John", "first_name"=>"John", "last_name"=>"Smith",
"link"=>"http://www.facebook.com/ujifgc", "username"=>"ujifgc", ... }
So, the username field is what you want.

Resources