That’s one common way of doing it.
Yet, it worked. Basically, visitor makes a request URL, which Rails
translates into a controller/action sequence. In order to determine fate
of URL request, we create a rule that matches the URL path of the
request and determine where to direct that request. It maps requests to
action methods inside the controllers. The mapper method parses the
query string as a hash. So when login is part of query string action
based on user clicking link, a URL request is made, the mapper method in
turn is called, and points the request to the login method of the users
class:
map.login “login”, :controller => “users”, :action => “login”
Since we are using named routing, Rails builds a helper method:
<%= link_to “login”, login_path %>
login method is called of UsersController class:
def login
@user = User.new
if request.post?
if session[:user] = User.authenticate(params[:user][:login],
params[:user][:password])
flash[:message] = “Login successful”
redirect_to :root
else
flash[:warning] = “Username or password does not exist”
end
end
end
We instantiate User class and assign the new instance to instance
variable @user. Hence, we have a @user object and since during
instantiation, our new instance inherits from ActiveRecord, the “blank”
instance in reality inherits getter setter methods translated from users
table in database. Hence, we accept parameters in the query string that
will translate to the data we need (e.g. login and password). Since the
instance variable inherits from ActiveRecord, it has access to some of
the built in rails helper methods like label, text_field,
password_field, submit:
<% content_for :login do %>
<% form_for @user, :url => { :action => “login” } do |f| %>
<%= error_messages_for ‘user’ %>
<%= f.label(:user_login, “Username”)%>
<%= f.text_field(:login) %>
<%= f.label(:user_password, “User Password”)%>
<%= f.password_field(:password) %>
<%= f.submit(“Login”) %>
<%= link_to 'Register', :action => 'signup' %> |
<%= link_to 'Forgot my password', :action => 'forgot_password' %>
<% end %>
<% end %>
The helper methods render html output. User inserts value and gets
converted to a hash with key/value pairs corresponding to field in table
to its value. Hence, we do the following in controller:
if request.post?
if session[:user] = User.authenticate(params[:user][:login],
params[:user][:password])
When the form is submitted a POST HTTP request is made, and we call the
class method authenticate on the User class object. We pass in the
relevant query string information using the params hash.
The authenticate method in turn is called:
def self.authenticate(login, pass)
u=find(:first, :conditions=>[“login = ?”, login])
return nil if u.nil?
return u if User.encrypt(pass, u.salt)==u.hashed_password
nil
end
We use special syntax self to indicate this is a class method and not an
instance method and therefore can only be called on the class itself. We
pass our query string arguments into the authenticate argument
definition as parameters (local variables) login and pass. We perform a
sql query to our mysql database, searching first record of login field
that matches value passed. We assign result to local variabnle u. If u
is nil, we return nil, and the if statement’s argument will be converted
to BOOLEAN false (which I believe is object not a primitive in ruby?):
if session[:user] = User.authenticate(params[:user][:login],
params[:user][:password])
Hence, else statement is invoked:
flash[:warning] = "Username or password does not exist"
Otherwise, we return u (the data set of current user):
return u if User.encrypt(pass, u.salt)==u.hashed_password
We do this if the encrupt method returns a value equal to what the
hashed_password method’s value is.
So returning u will convert the if booleon to true and if statement
returns immediate block:
flash[:message] = "Login successful"
redirect_to :root
The user is logged in successful.
One thing I forgot to mention is we assign the local variable u to the
session :user:
if session[:user] = User.authenticate(params[:user][:login],
params[:user][:password])
Hence, the session has this user stored.
THis is a little unclear to me though:
session[:user]
We are storing a symbol called :user in sesion associative array. So
:user is initiaized with vaue of u (whcih is dataset we returned).
What’s the purpose of using symbol here? Why can’t we use something else
like a variable?
THanks for response.