This is an update to my last post about Facebook Connect with a Rails app. At the time I was using facebooker plugin (yeah, a plugin, not a gem), which has been discontinued for the longest time, and thus wouldn’t work with current Facebook connect.
Since then, I’ve used omniauth, omniauth-facebook, and devise gems to implement Facebook connect with a few Rails app I have been toying with. So, this is kind of an update to my last post about integrating Facebook Connect with a Rails app.
1. First, you need the following gems in your Gemfile.
gem 'devise'
gem 'omniauth'
gem 'omniauth-facebook'
gem 'oauth2'
Make sure you install them by running “bundle install” command.
2. Next configure devise gem.
rails generate devise:install
3. Apply devise to a model. 99.9% of time, this would be the User model.
rails generate devise User
4. Next, generate authentication model with the following columns. Token column is extra, if you want to save an access token.
rails g model Authentication user_id:integer provider:string uid:string token:string
5. Configure omniauth by modifying config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
# The following is for facebook
provider :facebook, [APP ID], [SECRET KEY], {:scope => 'email, read_stream, read_friendlists, friends_likes, friends_status, offline_access'}
# If you want to also configure for additional login services, they would be configured here.
end
6. After user authenticates with whatever provider you specify, user needs to be redirected to omniauth call, so add the following line in your routes.rb.
match '/auth/:provider/callback' => 'authentications#create'
7. Then in Authentications controller, you figure out whether to create a new user or log the user in, if the user is an existing user. For complete hash, take a look at omniauth-facebook github page.
def create
auth = request.env["omniauth.auth"]
# Try to find authentication first
authentication = Authentication.find_by_provider_and_uid(auth['provider'], auth['uid'])
if authentication
# Authentication found, sign the user in.
flash[:notice] = "Signed in successfully."
sign_in_and_redirect(:user, authentication.user)
else
# Authentication not found, thus a new user.
user = User.new
user.apply_omniauth(auth)
if user.save(:validate => false)
flash[:notice] = "Account created and signed in successfully."
sign_in_and_redirect(:user, user)
else
flash[:error] = "Error while creating a user account. Please try again."
redirect_to root_url
end
end
end
8. In User model, store essential information with apply_omniauth method.
has_many :authentications, :dependent => :delete_all
def apply_omniauth(auth)
# In previous omniauth, 'user_info' was used in place of 'raw_info'
self.email = auth['extra']['raw_info']['email']
# Again, saving token is optional. If you haven't created the column in authentications table, this will fail
authentications.build(:provider => auth['provider'], :uid => auth['uid'], :token => auth['credentials']['token'])
end
9. In Authenication model,
belongs_to :user
10. In your view, user clicking on /auth/facebook/ link will be redirected to Facebook to log in.
<%= link_to 'Login with Facebook', '/auth/facebook/' %>