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,
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/' %> |
11. This method doesn’t do FB login in a popup. For that, you have to use FB Javascript SDK, and you can use the example here.