Facebook Authentication with Devise: Part 2

This is Part 2 of the Facebook Authentication with Devise series. For Part 1, click here.

The code for this tutorial can be found here.

When we left off last one of the questions remaining was how to let an existing user link their Facebook account rather than creating an account with Facebook first. Adding this functionality isn’t very difficult, just required a bit of tweaking to our existing code.

Updating our Callbacks Controller

Right now in our OmniauthCallbacksController we’re assuming that a user needs to be created. An easy way to fix this is to update our method to look like this:

def facebook
	if current_user.present?
		redirect_to edit_user_registration_path, notice: "Facebook Account Linked!"
		@user = User.from_omniauth(request.env["omniauth.auth"])
		sign_in_and_redirect @user

Here we’re checking to see if a user is signed in and executing the apply_omniauth method instead of the from_omniauth method if they are.

Updating our User Model

Next, we have to implement the new method in the User model.

def apply_omniauth(auth)
		provider: auth.provider,
		uid: auth.uid

This method is similar to our from_omniauth method, but instead of creating a new user, it is updating an existing one.

We’ll also want to provide a convenience method to see if a user has their Facebook account linked or not.

def has_facebook_linked?
	self.provider.present? && self.uid.present?

This method will come in handy when giving the user the ability to link/unlink their account in their account settings.

The Authentications Controller

Before we update the markup on our account settings page, we’re going to set up an authentications controller. This will let us add more third-party services (Twitter, LinkedIn, Gmail, etc.) in the future more easily.

$ rails g controller authentications

We’re going to manage destroying authentication method’s in this controller. Currently, the only method we have is Facebook so it will be pretty straight forward. First, we need to configure our routes.

resources :authentications, only: [:destroy]

Now we need to add the destroy method to our new controller.

class AuthenticationsController < ApplicationController
	def destroy
		current_user.update_attributes(provider: nil, uid: nil)
		redirect_to edit_user_registration_path, notice: "Facebook Account Unlinked"

This removes the information that Facebook provided us, unlinking the account.

Updating Our Account Settings Page

The logical place to add this linking/unlinking functionality is on our account settings page. When we first set up Devise we generated it’s views which are now located at app/views/devise/. We’re interested in the app/views/devise/registrations/edit.html.erb file. Below the <h2> tag and above the form, add the following:

<h3>Facebook Settings</h3>
<% if resource.has_facebook_linked? %>
	<%= link_to "Unlink Facebook", authentication_path(resource), method: :delete %>
<% else %>
	<%= link_to "Link Facebook", omniauth_authorize_path(:user, :facebook) %>
<% end %>

<h3>Account Settings</h3>

Now we’ve got the ability to link and unlink Facebook accounts with accounts in our system regardless of if the user signed up with Facebook or not!

Moving Forward

This still isn’t a complete solution! There are more scenarios to account for such as linking other social accounts and accessing more information from the users Facebook profile. Stay tuned for tutorials on how to address these issues and more!

The code for this tutorial can be found here.

Need help with a project? We'd love to hop on board. Hire Us.

Get In

Must be a valid email address.