Skip to content
This repository has been archived by the owner on Dec 12, 2021. It is now read-only.

Commit

Permalink
adding initial nifty authentication, still a lot of work to be done here
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanb committed Oct 10, 2008
1 parent cd369ec commit 21b22bc
Show file tree
Hide file tree
Showing 17 changed files with 369 additions and 3 deletions.
1 change: 1 addition & 0 deletions README.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ using the script/generate or script/destroy command.
* nifty_layout: generates generic layout, stylesheet, and helper files.
* nifty_scaffold: generates a controller and optional model/migration.
* nifty_config: generates a config YAML file and loader.
* nifty_authentication: simpler variation of restful_authentication.

Run the command with the --help option to learn more.

Expand Down
8 changes: 6 additions & 2 deletions TODO
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@

Nifty Scaffold Generator
Nifty Scaffold
- add some validation for attributes/action names
- refactor out long methods in scaffold generator

Nifty Config Generator
Nifty Config
- make it easier to specify non environment specific configs

Nifty Authentication
- add HAML support
- generate tests for should, rspec, and testunit
27 changes: 27 additions & 0 deletions rails_generators/nifty_authentication/USAGE
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Description:
Generates a user model, users controller, and sessions controller. The
users controller handles the registration and the sessions controller
handles authentication. This is similar to restful_authentication, but
simpler.

IMPORTANT: This generator uses the "title" helper method which is generated
by the nifty_layout generator. You may want to run that generator first.

Usage:
If you do not pass any arguments, the model name will default to "user", and
the authentication controller will default to "sessions". You can override
each of these respectively by passing one or two arguments. Either name can
be CamelCased or under_scored.

Examples:
script/generate nifty_authentication

Creates user model, users_controller, and sessions_controller.

script/generate nifty_authentication account

Creates account model, accounts_controller, and sessions_controller.

script/generate nifty_authentication Account CurrentSession

Creates account model, accounts_controller, and current_sessions_controller.
54 changes: 54 additions & 0 deletions rails_generators/nifty_authentication/lib/insert_routes.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
Rails::Generator::Commands::Create.class_eval do
def route_resource(*resources)
resource_list = resources.map { |r| r.to_sym.inspect }.join(', ')
sentinel = 'ActionController::Routing::Routes.draw do |map|'

logger.route "map.resource #{resource_list}"
unless options[:pretend]
gsub_file 'config/routes.rb', /(#{Regexp.escape(sentinel)})/mi do |match|
"#{match}\n map.resource #{resource_list}\n"
end
end
end

def route_name(name, path, route_options = {})
sentinel = 'ActionController::Routing::Routes.draw do |map|'

logger.route "map.#{name} '#{path}', :controller => '#{route_options[:controller]}', :action => '#{route_options[:action]}'"
unless options[:pretend]
gsub_file 'config/routes.rb', /(#{Regexp.escape(sentinel)})/mi do |match|
"#{match}\n map.#{name} '#{path}', :controller => '#{route_options[:controller]}', :action => '#{route_options[:action]}'"
end
end
end
end

Rails::Generator::Commands::Destroy.class_eval do
def route_resource(*resources)
resource_list = resources.map { |r| r.to_sym.inspect }.join(', ')
look_for = "\n map.resource #{resource_list}\n"
logger.route "map.resource #{resource_list}"
unless options[:pretend]
gsub_file 'config/routes.rb', /(#{look_for})/mi, ''
end
end

def route_name(name, path, route_options = {})
look_for = "\n map.#{name} '#{path}', :controller => '#{route_options[:controller]}', :action => '#{route_options[:action]}'"
logger.route "map.#{name} '#{path}', :controller => '#{route_options[:controller]}', :action => '#{route_options[:action]}'"
unless options[:pretend]
gsub_file 'config/routes.rb', /(#{look_for})/mi, ''
end
end
end

Rails::Generator::Commands::List.class_eval do
def route_resource(*resources)
resource_list = resources.map { |r| r.to_sym.inspect }.join(', ')
logger.route "map.resource #{resource_list}"
end

def route_name(name, path, options = {})
logger.route "map.#{name} '#{path}', :controller => '{options[:controller]}', :action => '#{options[:action]}'"
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
require File.expand_path(File.dirname(__FILE__) + "/lib/insert_routes.rb")
class NiftyAuthenticationGenerator < Rails::Generator::Base
attr_accessor :user_name, :sessions_name

def initialize(runtime_args, runtime_options = {})
super
@user_name = @args[0] || 'user'
@sessions_name = @args[1] || 'sessions'
end

def manifest
record do |m|
m.directory "app/models"
m.directory "app/controllers"
m.directory "app/helpers"
m.directory "app/views"
m.directory "app/lib"
m.directory "app/config"
m.directory "app/config/initializers"

m.template "initializer.rb", "app/config/initializers/include_authentication.rb"

m.directory "app/views/users"
m.template "user.rb", "app/models/#{user_singular_name}.rb"
m.template "users_controller.rb", "app/controllers/#{user_plural_name}_controller.rb"
m.template "users_helper.rb", "app/helpers/#{user_plural_name}_helper.rb"
m.template "views/erb/signup.html.erb", "app/views/#{user_plural_name}/new.html.erb"

m.directory "app/views/sessions"
m.template "sessions_controller.rb", "app/controllers/#{sessions_underscore_name}_controller.rb"
m.template "sessions_helper.rb", "app/helpers/#{sessions_underscore_name}_helper.rb"
m.template "views/erb/login.html.erb", "app/views/#{sessions_underscore_name}/new.html.erb"

m.template "authentication.rb", "app/lib/authentication.rb"
m.migration_template "migration.rb", "db/migrate", :migration_file_name => "create_#{user_plural_name}"

m.route_resources user_plural_name
m.route_resources sessions_underscore_name
m.route_name :login, 'login', :controller => sessions_underscore_name, :action => 'new'
m.route_name :logout, 'logout', :controller => sessions_underscore_name, :action => 'destroy'
m.route_name :signup, 'signup', :controller => user_plural_name, :action => 'new'
end
end

def user_singular_name
user_name.underscore
end

def user_plural_name
user_singular_name.pluralize
end

def user_class_name
user_name.camelize
end

def user_plural_class_name
user_plural_name.camelize
end

def sessions_underscore_name
sessions_name.underscore
end

def sessions_class_name
sessions_name.camelize
end

protected

def banner
<<-EOS
Creates user model and controllers to handle registration and authentication.
USAGE: #{$0} #{spec.name} [user_name] [sessions_controller_name]
EOS
end
end
20 changes: 20 additions & 0 deletions rails_generators/nifty_authentication/templates/authentication.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module Authentication
def self.included(controller)
controller.send :helper_method, :current_<%= user_singular_name %>, :logged_in?
end

def current_<%= user_singular_name %>
@current_<%= user_singular_name %> ||= <%= user_class_name %>.find(session[:<%= user_singular_name %>_id]) if session[:<%= user_singular_name %>_id]
end

def logged_in?
current_<%= user_singular_name %>
end

def login_required
unless logged_in?
flash[:error] = "You must first log in or sign up before accessing this page."
redirect_to login_url
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ActionController::Base.send(:include, Authentication)
15 changes: 15 additions & 0 deletions rails_generators/nifty_authentication/templates/migration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class Create<%= user_plural_class_name %> < ActiveRecord::Migration
def self.up
create_table :<%= user_plural_name %> do |t|
t.column :username, :string
t.column :email, :string
t.column :password_hash, :string
t.column :password_salt, :string
t.timestamps
end
end

def self.down
drop_table :<%= user_plural_name %>
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
class <%= sessions_class_name %>Controller < ApplicationController
def new
end
def create
<%= user_singular_name %> = <%= user_class_name %>.authenticate(params[:login], params[:password])
if <%= user_singular_name %>
flash[:notice] = "Logged in successfully."
redirect_to root_url
else
flash[:error] = "Invalid login or password."
render :action => 'new'
end
end

def destroy
session[:<%= user_singular_name %>_id] = nil
flash[:notice] = "You have been logged out."
redirect_to root_url
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module <%= sessions_class_name %>Helper
end
33 changes: 33 additions & 0 deletions rails_generators/nifty_authentication/templates/user.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
class <%= user_class_name %> < ActiveRecord::Base
# new columns need to be added here to be writable through mass assignment
attr_accessible :username, :email, :password, :password_confirmation
attr_accessor :password
before_create :prepare_password
validates_presence_of :username
validates_format_of :email, :with => /^[-a-z0-9_+\.]+\@([-a-z0-9]+\.)+[a-z0-9]{2,4}$/i
validates_presence_of :password, :on => :create
validates_confirmation_of :password

# login can be either username or email address
def self.authenticate(login, pass)
<%= user_singular_name %> = find_by_username(login) || find_by_email(login)
return <%= user_singular_name %> if <%= user_singular_name %> && <%= user_singular_name %>.matching_password?(pass)
end

def matching_password?(pass)
self.password_hash == encrypt_password(pass)
end

private

def prepare_password
self.password_salt = Digest::SHA1.hexdigest([Time.now, rand].join)
self.password_hash = encrypt_password(password)
end

def encrypt(pass)
Digest::SHA1.hexdigest(pass + password_salt)
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class <%= user_plural_class_name %>Controller < ApplicationController
def new
@<%= user_singular_name %> = <%= user_class_name %>.new
end
def create
@<%= user_singular_name %> = <%= user_class_name %>.new(params[:<%= user_singular_name %>])
if @<%= user_singular_name %>.save
flash[:notice] = "Thank you for signing up!"
redirect_to root_url
else
render :action => 'new'
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module <%= user_plural_class_name %>Helper
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<%% title "Log in" %>

<%% form_tag sessions_path do %>
<p>
<%%= label_tag :login, "Username or Email Address" %><br />
<%%= text_field_tag :login, params[:login] %>
</p>
<p>
<%%= label_tag :password %><br />
<%%= password_field_tag :password %>
</p>
<p><%%= submit_tag "Log in" %></p>
<%% end %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<%% title "Sign up" %>

<%% form_for :<%= user_singular_name %> do |f| %>
<%%= f.error_messages %>
<p>
<%%= f.label :username %><br />
<%%= f.text_field :username %>
</p>
<p>
<%%= f.label :email, "Email Address" %><br />
<%%= f.text_field :email %>
</p>
<p>
<%%= f.label :password %><br />
<%%= f.password_field :password %>
</p>
<p>
<%%= f.label :password_confirmation, "Confirm Password" %><br />
<%%= f.password_field :password_confirmation %>
</p>
<p><%%= f.submit "Sign up" %></p>
<%% end %>
58 changes: 58 additions & 0 deletions test/test_nifty_authentication_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
require File.join(File.dirname(__FILE__), "test_helper.rb")

class TestNiftyAuthenticationGenerator < Test::Unit::TestCase
include NiftyGenerators::TestHelper

# Some generator-related assertions:
# assert_generated_file(name, &block) # block passed the file contents
# assert_directory_exists(name)
# assert_generated_class(name, &block)
# assert_generated_module(name, &block)
# assert_generated_test_for(name, &block)
# The assert_generated_(class|module|test_for) &block is passed the body of the class/module within the file
# assert_has_method(body, *methods) # check that the body has a list of methods (methods with parentheses not supported yet)
#
# Other helper methods are:
# app_root_files - put this in teardown to show files generated by the test method (e.g. p app_root_files)
# bare_setup - place this in setup method to create the APP_ROOT folder for each test
# bare_teardown - place this in teardown method to destroy the TMP_ROOT or APP_ROOT folder after each test
context "routed" do
setup do
Dir.mkdir("#{RAILS_ROOT}/config") unless File.exists?("#{RAILS_ROOT}/config")
File.open("#{RAILS_ROOT}/config/routes.rb", 'w') do |f|
f.puts "ActionController::Routing::Routes.draw do |map|\n\nend"
end
end

teardown do
FileUtils.rm_rf "#{RAILS_ROOT}/config"
end

context "generator without arguments" do
rails_generator :nifty_authentication
should_generate_file 'app/models/user.rb'
should_generate_file 'app/controllers/users_controller.rb'
should_generate_file 'app/helpers/users_helper.rb'
should_generate_file 'app/views/users/new.html.erb'
should_generate_file 'app/controllers/sessions_controller.rb'
should_generate_file 'app/helpers/sessions_helper.rb'
should_generate_file 'app/views/sessions/new.html.erb'
should_generate_file 'app/lib/authentication.rb'
should_generate_file 'app/config/initializers/include_authentication.rb'

should "generate migration file" do
assert !Dir.glob("#{RAILS_ROOT}/db/migrate/*.rb").empty?
end

should "generate routes" do
assert_generated_file "config/routes.rb" do |body|
assert_match "map.resources :sessions", body
assert_match "map.resources :users", body
assert_match "map.login 'login', :controller => 'sessions', :action => 'new'", body
assert_match "map.logout 'logout', :controller => 'sessions', :action => 'destroy'", body
assert_match "map.signup 'signup', :controller => 'users', :action => 'new'", body
end
end
end
end
end
Loading

0 comments on commit 21b22bc

Please sign in to comment.