Register now and start sharing your code snippets.

How to add OpenID support to your Rails application with the open_id_authentication plugin

Ruby posted 5 months ago by christian

These instructions have been tested with Rails 2.0.2 and ruby-openid 2.0.4. The snippet is an adaptation of the instructions in Ryan Bates’ screencast on how to integrate OpenID with Rails.

Installing and configuring the restful_authentication plugin

Follow these instructions: How to install and use the restful_authentication Rails plugin.

Installing the ruby-openid gem

   1  gem install ruby-openid

Installing the open_id_authentication Rails plugin

   1  script/plugin source http://svn.techno-weenie.net/projects/plugins/
   2  script/plugin install open_id_authentication

Create the migration files

   1  rake open_id_authentication:db:create

Add the following to the self.up method in 002_add_open_id_authentication_tables.rb:

   1  add_column :users, :identity_url, :string

Configuring the routes

   1  map.open_id_complete 'session', :controller => "sessions", :action => "create", :requirements => { :method => :get }

Protect the identity_url field

Next protect the identity_url field, by adding the following to user.rb, account.rb or your custom user model:

   1  attr_accessible :login, :email, :password, :password_confirmation, :identity_url

Add the following to the self.down method in 002_add_open_id_authentication_tables.rb:

   1  remove_column :users, :identity_url

Integrating Open-id with the login page

Add the following to sessions/new.html.erb:

   1  <label for="openid_url">OpenID URL</label><br />
   2  <%= text_field_tag "openid_url" %>

Make sure you’re showing flash messages, otherwise you won’t see the error messages:

   1  <html>
   2    <head></head>
   3    <body>
   4      <%= [:notice, :error].collect {|type| content_tag('div', flash[type], :id => type) if flash[type] } %>
   5  
   6      <%= yield %>
   7    </body>
   8  </html>

Modifying the sessions controller

Copy & paste the following code in app/controllers/sessions_controller.rb:

   1  class SessionsController < ApplicationController
   2    # Hack to fix: No action responded to show
   3    def show
   4      create
   5    end
   6  
   7    def create
   8      if using_open_id?
   9        open_id_authentication(params[:openid_url])
  10      else
  11        password_authentication(params[:login], params[:password])
  12      end
  13    end
  14  
  15    def destroy
  16      self.current_user.forget_me if logged_in?
  17      cookies.delete :auth_token
  18      reset_session
  19      flash[:notice] = "You have been logged out."
  20      redirect_back_or_default('/')
  21    end
  22  
  23    protected
  24  
  25    def open_id_authentication(openid_url)
  26      authenticate_with_open_id(openid_url, :required => [:nickname, :email]) do |result, identity_url, registration|
  27        if result.successful?
  28          @user = User.find_or_initialize_by_identity_url(identity_url)
  29          if @user.new_record?
  30            @user.login = registration['nickname']
  31            @user.email = registration['email']
  32            @user.save(false)
  33          end
  34          self.current_user = @user
  35          successful_login
  36        else
  37          failed_login result.message
  38        end
  39      end
  40    end
  41  
  42    def password_authentication(login, password)
  43      self.current_user = User.authenticate(login, password)
  44      if logged_in?
  45        successful_login
  46      else
  47        failed_login
  48      end
  49    end
  50  
  51    def failed_login(message = "Authentication failed.")
  52      flash.now[:error] = message
  53      render :action => 'new'
  54    end
  55  
  56    def successful_login
  57      if params[:remember_me] == "1"
  58        self.current_user.remember_me
  59        cookies[:auth_token] = { :value => self.current_user.remember_token , :expires => self.current_user.remember_token_expires_at }
  60      end
  61      redirect_back_or_default('/')
  62      flash[:notice] = "Logged in successfully"
  63    end
  64  end

OpenID authentication from behind a proxy

First, set the HTTP _PROXY environment variable to the proxy URL :

   1  export HTTP_PROXY=http://proxy.aktagon.com:8080/

Then add the following to environment.rb:

   1  OpenID::fetcher_use_env_http_proxy

Tagged openid, authentication, rails, ruby, plugin, restful_authentication

How to create an autocompleted field with jQuery, which looks and feels like autocomplete with Scriptaculous & prototype

JavaScript posted 6 months ago by christian

There are a lot of autocomplete plugins for jQuery, but not one of them seems to work similarly to Scriptaculous, except for the one at bassistance.de.

To use it follow the instructions found here.

There are a couple of gotchas for ex-scriptaculous users, like that the controller should return the list of tags with a newline character as separator, compared to an HTML list with Scriptaculous.

The other gotcha is the syntax, which is a lot prettier than Scriptaculous:

   1  <script type="text/javascript">
   2  $("#tags-field").autocomplete("/tags/autocomplete", {
   3  	multiple: true,
   4  	autoFill: true,
   5  	minChars: 3
   6  });
   7  </script>

Remember that /tags/autocomplete should render a list of tags delimited by linefeeds:

   1  ruby
   2  php
   3  java
   4  perl
   5  python

Note that jQuery sends the user typed text in a request parameter named ‘q’, so jQuery makes the following request to your controller: ’/tags/autocomplete?q=ruby’.

The list that’s shown when you type something can be styled with these CSS rules:

   1  div.ac_results {
   2  	width: 350px;
   3  	background: #fff;
   4  }
   5  
   6  div.ac_results ul {
   7  	border:1px solid #888;
   8  	margin:0;
   9  	padding:0;
  10  	width:100%;
  11  	list-style-type:none;
  12  }
  13  
  14  div.ac_results ul li {
  15  	margin:0;
  16  	padding:3px;
  17  }
  18  
  19  // Hovering over list item
  20  div.ac_results ul li.ac_over {
  21  	background-color: #ffb;
  22  }

The plugins documentation is quite good, but for some reason it was easier to figure out what was needed to get it working by reading the code.

Tagged jquery, autocomplete, plugin, scriptaculous, prototype