Topic: RoR 2.0.2 :: Very simple authentication from scratch in 15 steps

RoR 2.0.2 :: Very simple authentication from scratch in 15 steps

1.- rails pm -d mysql [ Creating a rails project called pm ]

2.- cd pm [ Change directory to the pm directory ]

3.- Edit your config/database.yml with your db user/password [ No explanation required ]

4.- rake db:create:all
[ This will create 3 databases: pm_development,pm_test,pm_production
* Nice thing would be to see a message of the result of what is doing perhaps in future releases ]

5.- ruby script\generate scaffold project title:string description:text [ Create files & migration files for a projects table with the fields title & description - yes timestamp will be by default included ]

6.- ruby script\generate controller sessions login logout [ This controller will take care of the authentication ]

7.- lets run our migration...
rake db:migrate
c:\ruby\railapps\pm>rake db:migrate
(in c:/ruby/railapps/pm)
== 1 CreateProjects: migrating ================================================
-- create_table(:projects)
   -> 0.0940s
== 1 CreateProjects: migrated (0.0940s) =======================================


8.- Let's secure the Index Projects page for the New Project:
#app/views/projects/index.html.erb
Replace:

    <td><%= link_to 'Show', project %></td>
    <td><%= link_to 'Edit', edit_project_path(project) %></td>
    <td><%= link_to 'Destroy', project, :confirm => 'Are you sure?', :method => :delete %></td>

With:
    <td><%= link_to 'Show', project %></td>

    <% if admin? %>
    <td><%= link_to 'Edit', edit_project_path(project) %></td>
    <td><%= link_to 'Destroy', project, :confirm => 'Are you sure?', :method => :delete %></td>
    <% end %>


...

at the end of the file apply for the new project:
...

    <% if admin? %>
<%= link_to 'New project', new_project_path %>
    <% end %>

[ This will only show the Edit and Destroy links if admin? is true ]

9.- Lets declare this important admin? method in the Application Controller to make it accessible for all the models.
#app/controller/application.rb

class ApplicationController < ActionController::Base
  helper :all # include all helpers, all the time

Add the following code:
  helper_method :admin?

  protected
  def authorize
    unless admin?
      flash[:error] = "unauthorized access"
      redirect_to home_path
      false
    end
  end

  def admin?
    session[:password] == 'railsforum'
  end


[ A couple questions will raise here...
the first part helper_method :admin? make the admin? method available on the view.
the second part will default the password to 'railsforum' not the best practice this is just for learning purposes. perhaps phase 2 will be to encrypt this password or retrieve from a DB Table.
the third part for the authorize method will check for the validation of the admin? object and redirect to home_path (this does not exist yet but will be ;-) please be patient... ) in case of failure.

10.- In the projects controller file add a before_filter method to perform the authorize validation previously declared
#app/controller/projects_controller.rb

class ProjectsController < ApplicationController
  # GET /projects

To:
class ProjectsController < ApplicationController
  before_filter :authorize, :except => :index

  # GET /projects....


11.- Lets create 2 methods on the sessions controller to perform the authentication:
#app/controller/sessions_controller.rb
class SessionsController < ApplicationController

  def login
  end

  def logout
  end
end


Change to:
class SessionsController < ApplicationController

  def create
    session[:password] = params[:password]
    flash[:notice] = "Successfully logged in"
    redirect_to home_path
  end


  def destroy
    reset_session
    flash[:notice] = "Successfully logged out"
    redirect_to login_path
  end

end


12.- In order to permit our application to access the login / logout pages lets add to the routes...
#config/routes.rb
ActionController::Routing::Routes.draw do |map|
  map.resources :projects

Change to:
ActionController::Routing::Routes.draw do |map|
  map.resources :projects, :sessions
  map.home '', :controller => 'projects', :action => 'index'
  map.login 'login', :controller => 'sessions', :action => 'new'
  map.logout 'logout', :controller => 'sessions', :action => 'destroy'

This will add the :sessions controller to the resources.
Also provide a default index page (yes we still need to delete the default index page public/index.html)
With the map.login give us the url path /login or /logout and route it to the sessions controller using the appropiate action.

13.- Remove the default index.html file located at: public/index.html


14.- The last thing to do is to create the content of the /login page. [This particular trick took me a little bit to understand since is just on the view. Create a file called 'new.html.erb' just like the action described on the routes file, since we created all this on the begining just rename the file called login.html.erb to new.html.eb.
#mv app/views/sessions/login.html.erb app/views/sessions/new.html.erb

Edit the file and enter the form for the Login:

<h1>Sessions#login</h1>
<p>Find me in app/views/sessions/login.html.erb</p>

change to:
<center>
    <% form_tag sessions_path do %>
      Password <%= password_field_tag :password %>
    <% end %>
</center>

[ This is the simple login form used to authenticate ]



#app/views/sessions/logout.html.erb

<h1>Sessions#logout</h1>
<p>Find me in app/views/sessions/logout.html.erb</p>

Change to:
<center>
    <h3> Successfully Logout </h3>
</center>

15.- Everything is ready let's launch the web server

script\server

To start will show:
Listing projects
Title     Description
At this point there is no projects in the application.

Let's login:
http://127.0.0.1:3000/login

As password enter "railsforum" then hit enter... feel free to play with your projects application.

Once your are ready to leave the site go to:
http://127.0.0.1:3000/logout

Yes I know a link will be more appropiate but feel free to tweak your needs.

That's All, I hope you enjoy and learn something else today, yes there are many other ways to do it, this is just a particular solution for a very small scale requirements, but surely fits my needs ;-)

I want to thank Ryan Bates for his great work on www.railscasts.com - This tutorial is inspired in his awesome work on the videos 20-21-22. I never could learn as much about rails in a short period of time without the help & inspiration of his screencasts.. yes yes... some books, peepcode, and a lot online research...

Features:
Provide security to a RoR application with a very simple controller.
More learning about the methods in the view & the smart usage of routes.
To learn more about how everything works behind the scenes not just plugin usage ;-)

Todo:
Enable the keep an MD5 of the password instead of plain text.
Combine with previous application with Permalinks: http://www.railsforum.com/viewtopic.php?id=14236 and setup a  more complete application with authentication.
Enable a little bit more complex authentication with user/password/groups... to allow small teams to interact in a very simple way without the complexity of another table on the DB.

It's that time of the year and I will enjoy the SuperBowl from Toluca, Mexico, go Rails Go, yes Go Patriots GO!!!
Din00z.

Last edited by dinooz (2008-03-03 13:55:54)

Re: RoR 2.0.2 :: Very simple authentication from scratch in 15 steps

Yeah, a logout link is more convenient for sure tongue but pretty good method dinooz (and quick too). I would probably waste ten times more code to achieve what you did with just a little bit of coding. I will try to implement your method.

Thanks,
Oliver [at] hemorrhoid treatment X dot Org.

Last edited by Oliverk48 (2011-04-01 11:02:44)

Re: RoR 2.0.2 :: Very simple authentication from scratch in 15 steps

Yeahh, the logic remained. May be some steps can be shortened today, but still thanks )
_________________________________________
iphone application development

Last edited by DaliMe (2011-05-29 07:57:15)

Re: RoR 2.0.2 :: Very simple authentication from scratch in 15 steps

Hi, i'm New to Rails, in this example, i think, no need to create logout.html.erb ?
suppose in my case when i redirect it to logout page through an hyperlink, it show message like

Re: RoR 2.0.2 :: Very simple authentication from scratch in 15 steps

Hi, Thanks for this guide, I have followed all the steps and getiing some error while running the server, can any one help me out...?
I'm using Rails 3.2.3
Ruby 1.9.2


/home/ali/pm/config/routes.rb:7:in `block in <top (required)>': undefined method `home' for #<ActionDispatch::Routing::Mapper:0x0000000126a808> (NoMethodError)
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/actionpack-3.2.3/lib/action_dispatch/routing/route_set.rb:282:in `instance_exec'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/actionpack-3.2.3/lib/action_dispatch/routing/route_set.rb:282:in `eval_block'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/actionpack-3.2.3/lib/action_dispatch/routing/route_set.rb:260:in `draw'
    from /home/ali/pm/config/routes.rb:1:in `<top (required)>'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/activesupport-3.2.3/lib/active_support/dependencies.rb:245:in `load'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/activesupport-3.2.3/lib/active_support/dependencies.rb:245:in `block in load'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/activesupport-3.2.3/lib/active_support/dependencies.rb:236:in `load_dependency'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/activesupport-3.2.3/lib/active_support/dependencies.rb:245:in `load'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/railties-3.2.3/lib/rails/application/routes_reloader.rb:40:in `block in load_paths'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/railties-3.2.3/lib/rails/application/routes_reloader.rb:40:in `each'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/railties-3.2.3/lib/rails/application/routes_reloader.rb:40:in `load_paths'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/railties-3.2.3/lib/rails/application/routes_reloader.rb:16:in `reload!'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/railties-3.2.3/lib/rails/application/routes_reloader.rb:26:in `block in updater'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/activesupport-3.2.3/lib/active_support/file_update_checker.rb:78:in `call'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/activesupport-3.2.3/lib/active_support/file_update_checker.rb:78:in `execute'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/railties-3.2.3/lib/rails/application/routes_reloader.rb:27:in `updater'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/railties-3.2.3/lib/rails/application/routes_reloader.rb:9:in `rescue in execute_if_updated'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/railties-3.2.3/lib/rails/application/routes_reloader.rb:7:in `execute_if_updated'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/railties-3.2.3/lib/rails/application/finisher.rb:66:in `block in <module:Finisher>'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/railties-3.2.3/lib/rails/initializable.rb:30:in `instance_exec'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/railties-3.2.3/lib/rails/initializable.rb:30:in `run'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/railties-3.2.3/lib/rails/initializable.rb:55:in `block in run_initializers'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/railties-3.2.3/lib/rails/initializable.rb:54:in `each'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/railties-3.2.3/lib/rails/initializable.rb:54:in `run_initializers'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/railties-3.2.3/lib/rails/application.rb:136:in `initialize!'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/railties-3.2.3/lib/rails/railtie/configurable.rb:30:in `method_missing'
    from /home/ali/pm/config/environment.rb:5:in `<top (required)>'
    from /home/ali/pm/config.ru:4:in `require'
    from /home/ali/pm/config.ru:4:in `block in <main>'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/rack-1.4.1/lib/rack/builder.rb:51:in `instance_eval'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/rack-1.4.1/lib/rack/builder.rb:51:in `initialize'
    from /home/ali/pm/config.ru:1:in `new'
    from /home/ali/pm/config.ru:1:in `<main>'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/rack-1.4.1/lib/rack/builder.rb:40:in `eval'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/rack-1.4.1/lib/rack/builder.rb:40:in `parse_file'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/rack-1.4.1/lib/rack/server.rb:200:in `app'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/railties-3.2.3/lib/rails/commands/server.rb:46:in `app'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/rack-1.4.1/lib/rack/server.rb:301:in `wrapped_app'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/rack-1.4.1/lib/rack/server.rb:252:in `start'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/railties-3.2.3/lib/rails/commands/server.rb:70:in `start'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/railties-3.2.3/lib/rails/commands.rb:55:in `block in <top (required)>'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/railties-3.2.3/lib/rails/commands.rb:50:in `tap'
    from /home/ali/.rvm/gems/ruby-1.9.2-p318/gems/railties-3.2.3/lib/rails/commands.rb:50:in `<top (required)>'
    from script/rails:6:in `require'
    from script/rails:6:in `<main>'