Facebook Connect with Rails (using Omniauth and Devise) [Update]

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/' %>

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.

44 thoughts on “Facebook Connect with Rails (using Omniauth and Devise) [Update]

  1. Pingback: metin2 hack

  2. Pingback: best service

  3. Pingback: How to integrate Facebook Feed with a Rails app « Yangtheman

  4. Pingback: How to integrate Facebook Connect with a Rails app « Yangtheman

  5. i m getting bellow error

    Bundler could not find compatible versions for gem “oauth2”:
    In Gemfile:
    omniauth-facebook (>= 0) ruby depends on
    oauth2 (~> 0.5.0) ruby

    oauth2 (0.4.1)

    please give solution

  6. This is an excellent guide but does not seem to work in the following 2 cases.

    1. User is already logged in but did have that specific authentication.

    2. There exists an user who already registered to the application with the email address that will be used on the facebook. This cause duplicate error in the db, and fails to proceed.

  7. Thanks for this article, it’s really cool and usefull.

    But,

    I’m getting this error when try to connect with facebook:
    {
    “error”: {
    “message”: “Invalid redirect_uri: La URL indicada no esta permitida por la configuraci\u00f3n de la aplicaci\u00f3n.”,
    “type”: “OAuthException”,
    “code”: 191
    }
    }

    in my initializer omniaguth.rb i just have this:

    Rails.application.config.middleware.use OmniAuth::Builder do
    provider :facebook, “335194483202896”, “608a8277064afd99d2c563c7d5a43e89”
    end

    • also i added the redirect uri on the omniauth.rb:

      provider :facebook, “335194483202896”, “608a8277064afd99d2c563c7d5a43e89”, :redirect_uri => “http://reelo.dev/auth/facebook/callback”

      but, I still getting the same error

      thanks for your help

      • You shouldn’t need to specify redirect_url in the omniauth.rb. Just add the following line in the routes.rb.

        match '/auth/:provider/callback' => 'authentications#create'
        

        Also, if you are testing it locally, you should make sure that you modify your hosts file to point your root domain to the loopback address.

  8. Hello! Nice post!

    I am getting the this error:

    /config/initializers/omniauth.rb:3: uninitialized constant ID (NameErro
    r)

    can you help?
    thanks!

    • Nervermind man…

      forgot to edit the app_id and the app_secret of my application.

      thanks!!!
      great post!!

  9. Is there a way to get the info, especially hometown, localized from Facebook? For example, I get “Munich, Germany” which would have to be “München, Deutschland”.

  10. Great one thanks ..

    One questions .
    How should i access public fb info for the user id now ?
    say username , photo url etc .

  11. Pingback: 关于的Devise+omniauth的用法文章搜集 | David's Blog

  12. Thanks for the tutorial,

    but i have a problem. When i’m connecting with facebook, devise wants to confirm the account. How skip the confirmation email, please ?

    • You can do it in two ways.

      Either remove :confirmable from user model, or

      Before saving the user instance, do “user.skip_confirmation!” followed by “user.save”.

  13. I keep getting this. What am I doing wrong?

    {
    “error”: {
    “message”: “Invalid redirect_uri: Given URL is not permitted by the application configuration.”,
    “type”: “OAuthException”,
    “code”: 191
    }
    }

  14. hi in my app i am using devise for authentication and for facebook authentication i followed u r tutorial described above…..
    but i m getting problem
    Routing Error

    No route matches [GET] “/auth/facebook”
    Try running rake routes for more information on available routes.

    but
    after runing rake routes i got

    /auth/:provider/callback(.:format) auth/:provider#callback

    its there

    my routes.rb

    match ‘/users/auth/:provider/callback’ ; ‘authentications#create’
    devise_for :admins,:controllers => {:sessions => “admin_sessions”,:registrations => “admin_registrations”,:passwords => “admin_passwords”,:confirmations => “admin_confirmations”}
    devise_scope :admins do
    match “/admins/admin_login_checking_at_sign_in”,:to =>”admins#admin_login_checking_at_sign_in”,:as=> “admin_login_checking_at_sign_in”
    end

    please help me out…..

    looking for u r reply
    thanks in advance

  15. Thanks for your post. It is very helpful. I’m getting the following error: Could not find a valid mapping for # is OK
    I followed the steps in your blog without understanding omniauth. I’d appreciate any clues to what may be causing this issue. Thanks again!

    • The error is: Could not find a valid mapping for #<User id: 1,1, name: "[myName]", uid: [myUid], created_at: "2012-12-10 23:49:28",….

      I meant to say that User.all produces the correct results. Thanks!

  16. This move transforms Facebook from being a social
    network to being quasi-White Pages of the Web. But when people click on your search listing, they wont be able to see
    all of the information in your profile (timeline).
    Facebook messages can be open for all to see, and even private messages can be viewed by authorities through search
    warrants in more open countries or pressure on the Internet social
    media firms in more closed ones.

Leave a Reply

Your email address will not be published. Required fields are marked *