Devise + OmniAuth + Facebook (what happens there)

I was curious what’s happening under the hood when facebook authentication is enabled. I specified some breakpoints in my RubyMine to find out in which order the particular methods are called.

The integration of Facebook consists of these steps: (for more information read https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview):

  • adding some gems to Gemfile:

    #facebook integration
    gem 'omniauth'
    gem 'omniauth-facebook'
    gem 'omniauth-twitter'
    gem 'omniauth-linkedin'
    
  • Adding new columns to the table:

    bundle install
    rails g migration AddColumnsToUsers provider uid #note: name is already there
    rake db:migrate
    
  • make the new columns accessible (for mass assignment):

    # User model
    attr_accessible :provider, :uid
    
  • extending config by adding the facebook configuration:

    # initializers/devise.rb:
    # require the gem and add it to the config!
    
      require "omniauth-facebook"
      config.omniauth :facebook, "5745245454154", "5ecd0a644303fab5c19dfdfdf383d06", #your APP_ID and APP_SECRET
                      #for heroku necessary (development env. works as well)
                      {:strategy_class => OmniAuth::Strategies::Facebook,
                       :scope => 'email, offline_access',
                       :client_options => {:ssl => {:ca_file => '/usr/lib/ssl/certs/ca-certificates.crt'}}}
    
  • user model must have to class instance methods (see link above):

    
    #### User model must have:
    
    find_for_facebook_oauth
    find_in_session
    
  • User model must make itself “omniauthable”:

    devise : omniauthable, : omniauth_providers => [:facebook]
    
  • we need an additional controller for handling authentication provider method (facebook, twitter, …)

    #### Users controller must have a "sub controller":
    Users::OmniauthCallbacksController with facebook method.
    
  • we actually don’t need to add a link any view. The links are rendered automatically in this partial:

    /devise/shared/_links.html.erb partial
    
  • routes.rb file must be updated accordingly:

      devise_for :users, :controllers => { : omniauth_callbacks => "users/omniauth_callbacks" }
      resources :users
    

When everything is in place I can start a short debug session just to understand what’s going on and where RoR will step in.

facebook_devise_integration_sequence

I think the content of the image is self-explanatory. Devise maps the particular URLs to the actions in the controllers this way:

                    root          /                                      home#index
                    root          /                                      home#index
        new_user_session GET      /users/sign_in(.:format)               devise/sessions#new
            user_session POST     /users/sign_in(.:format)               devise/sessions#create
    destroy_user_session DELETE   /users/sign_out(.:format)              devise/sessions#destroy
           user_password POST     /users/password(.:format)              devise/passwords#create
       new_user_password GET      /users/password/new(.:format)          devise/passwords#new
      edit_user_password GET      /users/password/edit(.:format)         devise/passwords#edit
                         PUT      /users/password(.:format)              devise/passwords#update
cancel_user_registration GET      /users/cancel(.:format)                devise/registrations#cancel
       user_registration POST     /users(.:format)                       devise/registrations#create
   new_user_registration GET      /users/sign_up(.:format)               devise/registrations#new
  edit_user_registration GET      /users/edit(.:format)                  devise/registrations#edit
                         PUT      /users(.:format)                       devise/registrations#update
                         DELETE   /users(.:format)                       devise/registrations#destroy
 user_omniauth_authorize GET|POST /users/auth/:provider(.:format)        users/omniauth_callbacks#passthru {:provider=>/facebook/}
  user_omniauth_callback GET|POST /users/auth/:action/callback(.:format) users/omniauth_callbacks#(?-mix:facebook)
                   users GET      /users(.:format)                       users#index
                         POST     /users(.:format)                       users#create
                new_user GET      /users/new(.:format)                   users#new
               edit_user GET      /users/:id/edit(.:format)              users#edit
                    user GET      /users/:id(.:format)                   users#show
                         PUT      /users/:id(.:format)                   users#update
                         DELETE   /users/:id(.:format)                   users#destroy
Advertisements

Heroku deploy / pre-compile custom assets

If you deploy your Rails Application to Heroku, you might obtain following error that is actually logged into the log and can be printed by heroku logs:

2012-12-01T19:14:19+00:00 app[web.1]: Completed 500 Internal Server Error in 3ms
2012-12-01T19:14:19+00:00 app[web.1]: 
2012-12-01T19:14:19+00:00 app[web.1]: ActionView::Template::Error (blueprint/blueprint/screen.css isn't precompiled):

Continue reading

Visitor Pattern Revisited

Today, I encountered the visitor pattern in the SLD implementation inside Geotools. This is reason enough to consider this pattern in the world of Ruby. Especially because I read recently this post where visitor is supposed to be more an antipattern that a pattern. This is because Ruby supports extension of objects at runtime. Nevertheless, I need to check it out!

A simple implementation of a Visitor is accomplished in 3 steps:

Continue reading

Factory Pattern Revisited

Recently I read here that there are GOF patterns which cannot be applied for every language (in Ruby, metaprogramming takes place so that some patterns are unnecessary). But I’m sure that factories are still sexy, no matter what programming language is used. That’s simply an intelligent way to create objects in one place instead of scatter “new Type()” everywhere in your code. That’s true for Ruby as well.

Continue reading

Exploring Metaprogramming Idioms similar to RSpec

I have been learning Ruby for 2-3 months. At the beginning, I was very shocked by some approaches being used there.
Recently, I have been very excited about the powerful meta-programming features working very reliably. By the way, a few years ago, I tried to explain to people how difficult it is to deal with such dynamic languages like Javascript (and other ones as well) and how lucky Java programmers are because the have a compiler.

Continue reading