I am using omniauth-facebook gem. I need to fetch gender and email from facebook, but it is not happening. Can anyone help me out here?
User Model
class User < ActiveRecord::Base
attr_accessible :email, :name, :uid, :provider, :gender, :oauth_token, :oauth_expires_at
validates_presence_of :name, :uid
validates_uniqueness_of :uid
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_initialize.tap do |user|
user.provider = auth.provider
user.uid = auth.uid
user.name = auth.info.name
user.email = auth.info.email
user.gender = auth.info.gender
user.image = auth.info.image
user.save!
end
end
end
User Contoller
class UsersController < ApplicationController
respond_to :html, :json
def create
#user = User.from_omniauth(env["omniauth.auth"])
session[:user_id] = #user.id
redirect_to api_browsing_screen_url
end
end
omniauth.rb
OmniAuth.config.logger = Rails.logger
Rails.application.config.middleware.use OmniAuth::Builder do
if Rails.env.production?
provider :facebook, 'app_id', 'app_secret_key'
elsif Rails.env.development?
provider :facebook, 'app_id', 'app_secret_key', {:scope => 'publish_actions,email', :client_options => { :ssl => { :ca_file => "#{Rails.root}/config/ca-bundle.crt" }}}
else
provider :facebook, 'app_id', 'app_secret_key'
end
end
You can get gender attribute from extra.raw_info.gender. like below
user.gender = auth.extra.raw_info.gender
Related
I need to add the skip validation methods to my sessions controller but i am unsure what to define omniauth as and basic login as. Ie they are both from class User but in sessions controller do I put
def create
user = User.from_omniauth(env["omniauth.auth"])
**user.from_omniauth.skip_name_validation = true**
etc etc
Then also want to add validate for the methods in the model as put in bold and add that to my sessions controller so both instances of each login are able to be bypassed.
My sessions controller
def create
user = User.from_omniauth(env["omniauth.auth"])
unless user.present?
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
log_in user
redirect_to user
# Log the user in and redirect to the user's show page.
else
# Create an error message.
flash.now[:danger] = 'Invalid email/password combination'
render 'new'
end
else
log_in user
redirect_to user
end
end
My model.rb
class User < ApplicationRecord
before_save { self.email = email.downcase }
validates :name, presence: true, length: { maximum: 50 },
**unless: :skip_name_validation**
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false },
**unless: :skip_email_validation**
has_secure_password
validates :password, presence: true, length: { minimum: 6 }, allow_nil:true,
**unless: :skip_password_validation**
**attr_accessor :skip_name_validation, :skip_email_validation, :skip_password_validation**
**attr_accessor :skip_User, :skip_self**
**validate :User, unless: :skip_User**
**validate :self, unless: :skip_self**
def User.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.provider = auth.provider
user.uid = auth.uid
user.name = auth.info.name
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
user.save!
end
end
end
class User < ApplicationRecord
attr_accessor :password_confirmation, :skip_password_validation
validates :password, :presence => true ,unless: :skip_password_validation
validates_confirmation_of :password, :if => ->{ password.present? },unless: :skip_password_validation
def User.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.provider = auth.provider
user.uid = auth.uid
user.name = auth.info.name
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
user.save!
end
end
end
def create
user = User.from_omniauth(env["omniauth.auth"])
#######try this #####
user.skip_password_validation = true
####or try this ####
user.from_omniauth.skip_name_validation = true
unless user.present?
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
log_in user
redirect_to user
# Log the user in and redirect to the user's show page.
else
# Create an error message.
flash.now[:danger] = 'Invalid email/password combination'
render 'new'
end
else
log_in user
redirect_to user
end
end
I got some problem with OmniAuth FaceBook login into my webapp.
Tell me please, what should i edit to fix this error? Check the code.
Error in the browser:
undefined method `to_a' for "Name Surname":String
User.rb:
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
x = auth.info.name.to_a
user.name = x[0]
user.surname = x[1]
user.login = auth.info.uid
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
end
end
Omniauth_callback_controller.rb :
def facebook
if request.env["omniauth.auth"].info.email.blank?
redirect_to "/users/auth/facebook?auth_type=rerequest&scope=email"
end
#user = User.from_omniauth(request.env["omniauth.auth"])
if #user.persisted?
sign_in_and_redirect #user, :event => :authentication #this will throw if #user is not activated
set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format?
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
if(#user.surname.nil?)
redirect_to new_profile_path
else
redirect_to my_profile_path
end
end
end
devise.rb :
config.omniauth :facebook, '*********', '*********', {:client_options => {:ssl => {:verify => false}}}
name is a string and you are trying to convert it to array
x = auth.info.name.to_a
use split instead
x = auth.info.name.split
#=> ['Name', 'Surname']
You can make use of OmniAuth first_name and last_name:
Update your devise.rb:
config.omniauth :facebook, '*********', '*********', info_fields: 'email, first_name, last_name', {:client_options => {:ssl => {:verify => false}}}
and your user.rb:
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.name = auth.info.first_name
user.surname = auth.info.last_name
user.login = auth.info.uid
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
end
end
your user.rb should be like this
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
x = auth.info.name.split
if x.count > 1
user.name = x[0]
user.surname = x[1]
else
user.name = x[0]
end
user.login = auth.info.uid
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
end
end
But I would suggest to store in a single field, because name can be of more than two words so it would become difficult to identify name and surname.
this link should also help
I am trying to configure Google OAuth and I am facing a very silly mistake I can't solve :
When I click on the Sign in button on the home page:
<% if user_signed_in? %>
Signed in as <%= current_user.name %>. Not you?
<%= link_to "Sign out", destroy_user_session_path,:method => :delete %>
<% else %>
<%= link_to "Sign in with Google", user_omniauth_authorize_path(:google_oauth2) %>
<% end %>
I get this error undefined method find_for_google_oauth2 for #
It says the problem is at that line:
#user = user.find_for_google_oauth2(request.env["omniauth.auth"], current_user)
Here is my app/controllers/users/omniauth_callbacks_controller.rb:
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
# You need to implement the method below in your model (e.g. app/models/user.rb)
#user = User.from_omniauth(request.env["omniauth.auth"])
if #user.persisted?
sign_in_and_redirect #user, :event => :authentication #this will throw if #user is not activated
set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format?
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
def google_oauth2
#user = User.find_for_google_oauth2(request.env["omniauth.auth"], current_user)
if #user.persisted?
flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Google"
sign_in_and_redirect #user, :event => :authentication
else
session["devise.google_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
end
Here is my app/models/user.rb:
class User < ActiveRecord::Base
before_save :default_values
attr_accessor :delete_photo
validates :first_name, presence: true
validates :last_name, presence: true
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable, :omniauth_providers => [:facebook,:google_oauth2]
has_many :usertoskills
has_many :skills, through: :usertoskills
has_many :usertoprojects
has_many :projects, through: :usertoprojects
has_many :demands
has_many :news
has_attached_file :photo, :styles => { :small => "150x150>", :regular => "300x300>" },
:url => "/assets/users/:id/:style/:basename.:extension",
:path => ":rails_root/public/assets/users/:id/:style/:basename.:extension",
:default_url => "/assets/users/default/:style/default.jpg"
validates_attachment_content_type :photo, :content_type => ['image/jpeg', 'image/png']
#def name
# "#{self.first_name.camelize} #{self.last_name.camelize}"
#end
def default_values
if self.first_name && self.last_name
self.name = "#{self.first_name.camelize} #{self.last_name.camelize}"
end
end
def admin
self.role == 'admin'
end
def accessible_demands
if self.role == 'admin'
#demands = Demand.all
else
#demands = []
self.projects.each do |p| #demands.concat(p.demands) end
#demands = Demand.includes(:project).where(projects: { collective: true }, demands: {user_id: self.id}) | #demands
end
return #demands
end
def accessible_projects
if self.role == 'admin'
#projects = Project.all
else
#projects = self.projects
end
return #projects
end
def accessible_transactions
if self.role == 'admin'
#transactions = Transaction.all
else
#transactions = Transaction.where(sender_id: self.id)
end
end
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
#user.first_name = auth.info.first_name
#user.last_name = auth.info.last_name # assuming the user model has a name
#user.image = auth.info.image # assuming the user model has an image
end
def self.find_for_google_oauth2(access_token, signed_in_resource=nil)
data = access_token.info
user = User.where(:provider => access_token.provider, :uid => access_token.uid ).first
if user
return user
else
registered_user = User.where(:email => access_token.info.email).first
if registered_user
return registered_user
else
user = User.create(name: data["name"],
provider:access_token.provider,
email: data["email"],
uid: access_token.uid ,
password: Devise.friendly_token[0,20],
)
end
end
end
end
end
Thanks in advance for your help!
You have mismatched def and end calls in your class - you're missing an end after your def self.from_omniauth(auth) method. The where on the next line is incorrectly indented, hiding it. So in actuality, your find_for_google_oauth2 method is being defined inside your from_omniauth method.
This is one of the reasons that Ruby community conventions are really strict about a two-space indentation policy.
Here is my controller
def social_login
user = User.from_omniauth(env["omniauth.auth"])
session_params = user.attributes.merge("email" => user.email, "password" => user.crypted_password)
#user_session ||= UserSession.new(session_params, true)
if #user_session.save
user = User.where(email: #user_session.email).first
redirect_to root_path, :notice => "Signed in succesfully from #{env["omniauth.auth"].provider.titleize}. Greetings #{user.name.titleize} ;)"
else
flash.now[:alert] = "Sign in failed."
render "new"
end
end
here is the model to handle the omniauth process
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.provider = auth.provider
user.uid = auth.uid
user.name = auth.info.name
user.email = auth.info.email
user.password = auth.credentials.token
user.password_confirmation = auth.credentials.token
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
user.save!
end
end
I always getting error when trying to save the session. It says:
Authlogic::Session::Existence::SessionInvalidError: Your session is invalid and has the following errors: Email is not valid
can you guys help me? thanks
Did you enable the email permission in your facebook app config/rails's initializion?
Like this:
config.omniauth :facebook, "APP_ID", "APP_SECRET", {:scope => 'email,...'}
I am working on rails 3 and using the koala gem to get a connection to the facebook graph api.
And I am using omniauth to autenticate users.
So when a new user logs to the site, the session_controller handles the new user:
class SessionsController < ApplicationController
def create
user = User.from_omniauth(env['omniauth.auth'])
session[:user_id] = user.id
redirect_to root_url, notice: "Signed in!"
end
The create method call the "from_omniauth" class metod in the User.rb model, to create a new user:
class User < ActiveRecord::Base
has_many :friends
def self.from_omniauth(auth)
where(auth.slice(:provider, :uid)).first_or_initialize.tap do |user|
user.provider = auth["provider"]
user.uid = auth["uid"]
user.name = auth["info"]["name"]
user.first_name = auth["info"]["first_name"]
user.last_name = auth["info"]["last_name"]
user.image = auth["info"]["image"]
user.email = auth["info"]["email"]
user.gender = auth["extra"]["raw_info"]["gender"]
user.location = auth["extra"]["raw_info"]["location"]["name"]
user.token = auth["credentials"]["token"]
end
user.save!
end
I would like to save user facebook friends also and store it in a separate tabel called friends, so I made this friend model:
class Friend < ActiveRecord::Base
attr_accessible :name
belongs_to :user
validates :user_id, presence: true
def facebook
#Facebook ||= Koala::Facebook::API.new(token)
end
def add_friends
facebook { |fb| fb.get_connection("me", "friends") }
end
end
But I am lost on how to store users friends, I whould like to know:
How I can create a user, and store it friends
Where should I call the add_friends method?
fb.get_connection("me", "friends") return a array of hashes, like this > [{"name"=>"Johan Gyllenspetz", "id"=>"3624556"}, {"name"=>"Gustaf Josefsson", . And I would like to store the name and uid.
This is how I'd do this:
class User < ActiveRecord::Base
has_many :friends
def self.from_omniauth(auth)
user = where(auth.slice(:provider, :uid)).first_or_initialize.tap do |user|
user.provider = auth["provider"]
user.uid = auth["uid"]
user.name = auth["info"]["name"]
user.first_name = auth["info"]["first_name"]
user.last_name = auth["info"]["last_name"]
user.image = auth["info"]["image"]
user.email = auth["info"]["email"]
user.gender = auth["extra"]["raw_info"]["gender"]
user.location = auth["extra"]["raw_info"]["location"]["name"]
user.token = auth["credentials"]["token"]
end
user.add_friends
user.save
user
end
def add_friends
#facebook.get_connection("me", "friends").each do |hash|
self.friends.where(:name => hash['name'], :uid => hash['id']).first_or_create
end
end
private
def facebook
#facebook ||= Koala::Facebook::API.new(token)
end
end