Monday, December 10, 2007

Ruby On Rails Login module

Not a convert but a huge fan of Ruby on Rails(RoR). I feel Java and RoR will evolve as two separate eco-systems in future but that's a topic for another blog. In this one, I'm capturing the steps I followed in implementing the User registration for "numberconnect.com" (the first cut).

1. Installed Bitnami RubyOnRails stack
2. Run "rails" followed by the name of your desired application inside the Rails Environment:rails gorku
3. projects\gorku>ruby script\generate model User
4. projects\gorku>ruby script\generate controller Main
5. projects\gorku>edit db\migrate\001_create_users.rb
class CreateUsers < limit =""> 40
t.column "email", :string
t.column "email_confirmed", :boolean, :default => false
end
end
def self.down
drop_table :users
endend
6. Create the database and apply appropriate privileges
mysql\bin>mysql.exe -u root --port 3306 -p
mysql> CREATE DATABASE IF NOT EXISTS gorku_development;
mysql> CREATE DATABASE IF NOT EXISTS gorku_test;
mysql> CREATE DATABASE IF NOT EXISTS gorku_production;
mysql> GRANT ALL PRIVILEGES on gorku_development.* to 'root'@'localhost';
mysql> GRANT ALL PRIVILEGES on gorku_development.* to 'ODBC'@'localhost';
mysql> GRANT ALL PRIVILEGES on gorku_test.* to 'root'@'localhost';
mysql> GRANT ALL PRIVILEGES on gorku_test.* to 'ODBC'@'localhost';
mysql> GRANT ALL PRIVILEGES on gorku_production.* to 'root'@'localhost';
mysql> GRANT ALL PRIVILEGES on gorku_production.* to 'ODBC'@'localhost';
mysql> flush privileges;Query OK, 0 rows affected (0.18 sec)
6. projects\gorku>edit config\database.yml
development:
adapter: mysql
database: gorku_development
username: root
password: ******
host: localhost
7. projects\gorku>rake db:migrate
8. Quick Verification
mysql\bin>mysql.exe -u root --port 3306 -p
mysql> use gorku_development;
mysql> desc users;
9. Edit projects\gorku\app\controllers\main_controller.rb
class MainController <>edit routes.rb
# Add new routes
map.connect '', :controller => "main", :action => "index"
map.connect 'register', :controller => "main", :action => "register"
map.connect 'confirm_email/:hash', :controller => "main", :action => "confirm_email"
11. projects\gorku\app\views\main>edit index.rhtml


Welcome!

Click <%= link_to "here", :controller => "main", :action => "register" %>to register.


12. projects\gorku\app\views\main>edit register.rhtml


Register



username
<%= text_field "user", "username", "maxlength" => 20, "size" => 20 %>

email address
<%= text_field "user", "email", "maxlength" => 50, "size" => 20 %>

password
<%= password_field "user", "password", "maxlength" => 20, "size" => 20 %>

confirm password
<%= password_field "user", "confirm_password", "maxlength" => 20, "size" => 20 %>




13. Edit projects\gorku\app\controllers\main_controller.rb
def register
if request.get?
@user = User.new
else
@user = User.new(params[:user])

if @user.save
MailRobot::deliver_confirmation_email(@user, confirmation_hash(@user.username))
flash[:notice] = "Thank you for registering! We have sent a confirmation email to #{@user.email} with instructions on how to validate your account."
redirect_to(:action => "index")
end
end
# confirm an email address
def confirm_email
end

private

# create a hash to use when confirming User email addresses
def confirmation_hash(string)
Digest::SHA1.hexdigest(string + "secret word")
end
end
14. Edit projects\gorku\app\models\user.rb
require "digest/sha1"
class User < minimum =""> 4

attr_accessor :password, :confirm_password
# callback hooks
# validate that password and confirm_password match, and that email is proper format
def validate_on_create
@email_format = Regexp.new(/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/)
errors.add(:email, "must be a valid format") unless @email_format.match(email)
errors.add(:confirm_password, "does not match") unless password == confirm_password
errors.add(:password, "cannot be blank") unless !password or password.length > 0
end
# hash password before create
def before_create
self.hashed_password = User.hash_password(self.password)
end
# after creation, clear password from memory
def after_create
@password = nil
@confirm_password = nil
end
private
# hash password for storage in database
def self.hash_password(password)
Digest::SHA1.hexdigest(password)
end
# clean string to remove spaces and force lowercase
def self.clean_string(string)
(string.downcase).gsub(" ","")
end

end
15. projects\gorku>ruby script\generate mailer MailRobot
16. Edit projects\gorku\app\models\mail_robot.rb
class MailRobot < recipients =" user.email" from ="[user]@[domain].com"
@subject = "Confirm email address"
# email body substitutions go here
@body["username"] = user.username
@body["hash"] = hash
end
end
17. Create projects\gorku\app\views\mail_robot\confirmation_email.rhtml
,

Thank you for registering with our website. To confirm your email address, please visit the following address:

http://www.numberconnect.com/gorku/confirm_email/<%= @hash %>

- Friendly Mail Robot
18. Email projects\gorku\config\environment.rb” (if using dreamhost else http://wiki.rubyonrails.org/rails/pages/HowToSendEmailsWithActionMailer):
ActionMailer::Base.delivery_method = :sendmail
ActionMailer::Base.smtp_settings = {
:address => "smtp.gmail.com",
:port => 465,
:domain => "www.gmail.com",
:user_name => abc@gmail.com,
:password => "password",
:authentication => :login
}
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.raise_delivery_errors = true
ActionMailer::Base.default_charset = "utf-8"

For Numberconnect mail server the params would be:
ActionMailer::Base.smtp_settings = {
:address => "numberconnect.com",
:port => 25,
:domain => "www.numberconnect.com",
:user_name => "gosanjeev@numberconnect.com",
:password => "****",
:authentication => :login
}
19. Delete the file public/index.html
20. I'm done coding, need to test it out in the evening and then depoy the app on lunarpages
projects\gorku>ruby script\server

The App should work http://localhost:3000/

To make it work in Lunarpages, that's my next article...

Reference: http://technologyvoodoo.com/articles/user-registration-with-email-confirmation-in-ruby-on-rails

No comments: