I have 2 sign up options for users,
I added Twitter sign up later. There are some existing users sign up with email, how can I allow these existing users to link their Twitter account so that they can login either via email or twitter?
Thank you!
User Table:
create_table "designers", force: :cascade do |t|
t.string "fullname"
t.string "website"
t.string "bio"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "avatar"
t.string "slug"
t.string "twitter"
t.string "email", default: "", null: false
t.string "username"
t.string "location"
t.boolean "featured", default: false
t.string "twitter_username"
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.inet "current_sign_in_ip"
t.inet "last_sign_in_ip"
t.boolean "is_admin", default: false
t.string "provider"
t.string "uid"
t.index ["email"], name: "index_designers_on_email"
t.index ["reset_password_token"], name: "index_designers_on_reset_password_token", unique: true
end
omniauth_callbacks_controller
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def all
designer = Designer.from_omniauth(request.env['omniauth.auth'])
if designer.persisted?
sign_in_and_redirect designer, notice: "Signed in!"
else
session["devise.designer_attributes"] = designer.attributes
redirect_to new_designer_registration_url
end
end
alias_method :twitter, :all
end
registration_controller.rb
class RegistrationsController < Devise::RegistrationsController
def sign_up_params
params.require(:designer).permit(:username, :fullname, :email, :password, :password_confirmation)
end
def account_update_params
params.require(:designer).permit(:username, :fullname, :email, :location, :website, :twitter, :bio, :featured, :is_admin, :password, :password_confirmation, :current_password)
end
protected
def after_sign_up_path_for(resource)
edit_designer_path(current_designer) if current_designer
end
end
You should tell a bit more about your models and database, but the usual approach is:
You have an Identity model with some information like this:
Table Identities:
id serial NOT NULL
user_id integer, # The user in your Users table
provider text, # Linkedin, Twitter, Yahoo, any other provider
uid text, # Other data provided by the Oauth provider....
email text,
name text,
token text,
profile_url text,
image_url text,
secret text,
CONSTRAINT identities_pk PRIMARY KEY (id)
When your user subscribes or logs in using the Twitter button, you search him in the identities table to see if you already have it there (you search by provider and uid).
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def twitter
callback(:twitter)
end
def facebook
callback(:facebook)
end
def google
callback(:google)
end
def callback(provider)
@user = User.find_for_oauth(request.env["omniauth.auth"], current_user)
if @user.persisted?
sign_in_and_redirect @user, event: :authentication
set_flash_message(:success, :success, kind: "#{provider}".capitalize) if is_navigational_format?
else
session["devise.#{provider}_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
end
User Model
def self.find_for_oauth(auth, signed_in_resource = nil)
# Get the identity or create it if it does not exist
identity = Identity.find_for_oauth(auth)
user = signed_in_resource ? signed_in_resource : identity.user
# Create the user if needed (if no logged in user and the identity has no user associated)
if user.nil?
# Get the existing user by email if the provider gives us an email.
# If no email was provided we assign a temporary email and ask the
# user to verify it on the next step via UsersController.finish_signup
# email_is_verified = auth.info.email && (auth.info.verified || auth.info.verified_email)
email = auth.info.email
user = User.find_by(:email => email) if email
email ||= "#{TEMP_EMAIL_PREFIX}-#{auth.uid}-#{auth.provider}.com"
username = auth.info.nickname ? auth.info.nickname :
( auth.extra.raw_info.nickname ? auth.extra.raw_info.nickname :
( auth.extra.raw_info.username ? auth.extra.raw_info.username : "nickname: " + auth.uid) ) # Same as Identity.rb (in find_for_oauth)
new_username = username
# Create the user if it's a new registration.
# Use default values that will be updated later
if user.nil?
# Control if username is taken
user_same_name = User.find_by(:username => new_username)
while user_same_name
rnd = SecureRandom.random_number(10000).to_s
new_username = username + " (" + rnd + ")"
user_same_name = User.find_by(:username => new_username)
end
user = User.new(
name: auth.extra.raw_info.name,
username: new_username,
email: email,
password: Devise.friendly_token[0,20],
)
user.skip_confirmation!
user.save!
end
end
# Associate the identity with the user if needed
if identity.user != user
identity.user = user
identity.save!
end
user
end
Identity model
class Identity < ApplicationRecord
belongs_to :user
validates_presence_of :uid, :provider
validates_uniqueness_of :uid, :scope => :provider
def self.find_for_oauth(auth)
identity = find_or_create_by(uid: "nickname: " + auth.uid, provider: auth.provider) # Same as User.rb (in find_for_oauth)
identity.name = auth.extra.raw_info.name
identity.email = auth.info.email
identity.image_url = auth.info.image
identity.profile_url = nil
identity.token = auth.credentials.token
identity.secret = auth.credentials.secret
identity.save
identity
end
end
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.