How to add OpenID support to your Rails application with the open_id_authentication plugin
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
How to create an autocompleted field with jQuery, which looks and feels like autocomplete with Scriptaculous & prototype
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.