Hi!
I have just added login feature to my rails application by following the
instructions from "Agile Web Development with Rails" but now I am getting
strange error (looks to me like some kind of routing problem) under the
passenger/apache. It is working fine under webrick.
The error is:
500 Internal Server Error
The server encountered an internal error or misconfiguratio n and was
unable to complete your request.
From the log:
[4;36;1mSQL (0.3ms)[0m [0;1mSET SQL_AUTO_IS_NUL L=0[0m
Processing ****Controller# index (for 192.168.1.101 at 2010-04-26
18:56:24) [GET]
[4;35;1mUser Columns (1.7ms)[0m [0mSHOW FIELDS FROM `users`[0m
[4;36;1mUser Load (0.7ms)[0m [0;1mSELECT * FROM `users` WHERE
(`users`.`id` IS NULL) LIMIT 1[0m
Redirected to https://******/login/login_page
Filter chain halted as [:authorize] rendered_or_red irected.
Completed in 31ms (DB: 3) | 302 Found [https://******/]
Does anybody have any suggestion what I could do to fix this?
--------------------------------------------
class LoginController < ApplicationCont roller
def add_user
@user = User.new(params[:user])
if request.post? and @user.save
flash.now[:notice] = "User #{@user.name} created"
@user = User.new
end
end
def login_page
session[:user_id] = nil
if request.post?
user = User.authentica te(params[:name], params[:password])
if user
session[:user_id] = user.id
session[:user_name] = user.name
uri = session[:original_uri]
session[:original_uri] = nil
redirect_to(uri || { :action => "index" })
else
flash[:notice] = "Invalid user/password combination"
end
end
end
def logout
session[:user_id] = nil
flash[:notice] = "Logged out"
redirect_to(:ac tion => "login_page ")
end
def index
end
def delete_user
if request.post?
user = User.find(param s[:id])
if User.count == 1
flash[:notice] = "You can't remove last remaining user!"
else
user.destroy
end
end
redirect_to(:ac tion => :list_users)
end
def list_users
@all_users = User.find(:all)
end
end
------------------------------------------
class ApplicationCont roller < ActionControlle r::Base
before_filter :authorize, :except => :login_page
helper :all # include all helpers, all the time
protect_from_fo rgery # See ActionControlle r::RequestForge ryProtection
for details
def create_default_ variables(ctrl_ name)
session[:ctrl_name] = ctrl_name
end
# Scrub sensitive parameters from your log
# filter_paramete r_logging :password
private
def authorize
unless User.find_by_id (session[:user_id])
session[:original_uri] = request.request _uri
flash[:notice] = "Please log in"
redirect_to(:co ntroller => "login", :action => "login_page ")
end
end
end
------------------------------------------------
require 'digest/sha1'
class User < ActiveRecord::B ase
validates_prese nce_of :name
validates_uniqu eness_of :name
attr_accessor :password_confi rmation
validates_confi rmation_of :password
def validate
errors.add_to_b ase("Missing password") if hashed_password .blank?
end
def self.authentica te(name, password)
user = self.find_by_na me(name)
if user
expected_passwo rd = encrypted_passw ord(password, user.salt)
if user.hashed_pas sword != expected_passwo rd
user = nil
end
end
user
end
# 'password' is a virtual attribute
def password
@password
end
def password=(pwd)
@password = pwd
create_new_salt
self.hashed_pas sword = User.encrypted_ password(self.p assword,
self.salt)
end
def after_destroy
if User.count.zero ?
raise "Can't delete last user"
end
end
private
def self.encrypted_ password(passwo rd, salt)
string_to_hash = password + "wibble" + salt # 'wibble' makes it
harder to guess
Digest::SHA1.he xdigest(string_ to_hash)
end
def create_new_salt
self.salt = self.object_id. to_s + rand.to_s
end
end
-----------------------------------------
login_page.html .erb
<div class="user-form">
<fieldset>
<legend>Pleas e Log In</legend>
<% form_tag do %>
<p>
<label for="name">Name :</label>
<%= text_field_tag :name, params[:name] %>
</p>
<p>
<label for="password"> Password:</label>
<%= password_field_ tag :password, params[:password] %>
</p>
<p><%= submit_tag "Login" %></p>
<% end %>
</fieldset>
</div>
-------------------------------------------
routes.rb
ActionControlle r::Routing::Rou tes.draw do |map|
map.resources :controller1
map.resources :controller2
...
map.root :controller => "controller 1"
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
end
-------------------------------------------
and apache log:
[error] [client 192.168.1.101] Request exceeded the limit of 10 internal
redirects due to probable configuration error. Use
'LimitInternalR ecursion' to increase the limit if necessary. Use
'LogLevel debug' to get a backtrace.
"LogLevel debug" didn't produce any more information.
Update:
It is definitely routing problem.
I could partially solve the problem by adding this:
map.connect 'login', :controller => 'login', :action => "login_page "
map.connect 'login/list_users', :controller => "login", :action => "list_users "
map.connect 'login/add_user', :controller => "login", :action => "add_user"
map.connect 'login/logout', :controller => "login", :action => "logout"
to the routes.rb and just first line is working.
So redirecting to the <app>/login or typing it directly gives login_page action from the login controller.
The remaining problem is that I still can't use any action directly like /login/list_users or even login/login_page.
I have just added login feature to my rails application by following the
instructions from "Agile Web Development with Rails" but now I am getting
strange error (looks to me like some kind of routing problem) under the
passenger/apache. It is working fine under webrick.
The error is:
500 Internal Server Error
The server encountered an internal error or misconfiguratio n and was
unable to complete your request.
From the log:
[4;36;1mSQL (0.3ms)[0m [0;1mSET SQL_AUTO_IS_NUL L=0[0m
Processing ****Controller# index (for 192.168.1.101 at 2010-04-26
18:56:24) [GET]
[4;35;1mUser Columns (1.7ms)[0m [0mSHOW FIELDS FROM `users`[0m
[4;36;1mUser Load (0.7ms)[0m [0;1mSELECT * FROM `users` WHERE
(`users`.`id` IS NULL) LIMIT 1[0m
Redirected to https://******/login/login_page
Filter chain halted as [:authorize] rendered_or_red irected.
Completed in 31ms (DB: 3) | 302 Found [https://******/]
Does anybody have any suggestion what I could do to fix this?
--------------------------------------------
class LoginController < ApplicationCont roller
def add_user
@user = User.new(params[:user])
if request.post? and @user.save
flash.now[:notice] = "User #{@user.name} created"
@user = User.new
end
end
def login_page
session[:user_id] = nil
if request.post?
user = User.authentica te(params[:name], params[:password])
if user
session[:user_id] = user.id
session[:user_name] = user.name
uri = session[:original_uri]
session[:original_uri] = nil
redirect_to(uri || { :action => "index" })
else
flash[:notice] = "Invalid user/password combination"
end
end
end
def logout
session[:user_id] = nil
flash[:notice] = "Logged out"
redirect_to(:ac tion => "login_page ")
end
def index
end
def delete_user
if request.post?
user = User.find(param s[:id])
if User.count == 1
flash[:notice] = "You can't remove last remaining user!"
else
user.destroy
end
end
redirect_to(:ac tion => :list_users)
end
def list_users
@all_users = User.find(:all)
end
end
------------------------------------------
class ApplicationCont roller < ActionControlle r::Base
before_filter :authorize, :except => :login_page
helper :all # include all helpers, all the time
protect_from_fo rgery # See ActionControlle r::RequestForge ryProtection
for details
def create_default_ variables(ctrl_ name)
session[:ctrl_name] = ctrl_name
end
# Scrub sensitive parameters from your log
# filter_paramete r_logging :password
private
def authorize
unless User.find_by_id (session[:user_id])
session[:original_uri] = request.request _uri
flash[:notice] = "Please log in"
redirect_to(:co ntroller => "login", :action => "login_page ")
end
end
end
------------------------------------------------
require 'digest/sha1'
class User < ActiveRecord::B ase
validates_prese nce_of :name
validates_uniqu eness_of :name
attr_accessor :password_confi rmation
validates_confi rmation_of :password
def validate
errors.add_to_b ase("Missing password") if hashed_password .blank?
end
def self.authentica te(name, password)
user = self.find_by_na me(name)
if user
expected_passwo rd = encrypted_passw ord(password, user.salt)
if user.hashed_pas sword != expected_passwo rd
user = nil
end
end
user
end
# 'password' is a virtual attribute
def password
@password
end
def password=(pwd)
@password = pwd
create_new_salt
self.hashed_pas sword = User.encrypted_ password(self.p assword,
self.salt)
end
def after_destroy
if User.count.zero ?
raise "Can't delete last user"
end
end
private
def self.encrypted_ password(passwo rd, salt)
string_to_hash = password + "wibble" + salt # 'wibble' makes it
harder to guess
Digest::SHA1.he xdigest(string_ to_hash)
end
def create_new_salt
self.salt = self.object_id. to_s + rand.to_s
end
end
-----------------------------------------
login_page.html .erb
<div class="user-form">
<fieldset>
<legend>Pleas e Log In</legend>
<% form_tag do %>
<p>
<label for="name">Name :</label>
<%= text_field_tag :name, params[:name] %>
</p>
<p>
<label for="password"> Password:</label>
<%= password_field_ tag :password, params[:password] %>
</p>
<p><%= submit_tag "Login" %></p>
<% end %>
</fieldset>
</div>
-------------------------------------------
routes.rb
ActionControlle r::Routing::Rou tes.draw do |map|
map.resources :controller1
map.resources :controller2
...
map.root :controller => "controller 1"
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
end
-------------------------------------------
and apache log:
[error] [client 192.168.1.101] Request exceeded the limit of 10 internal
redirects due to probable configuration error. Use
'LimitInternalR ecursion' to increase the limit if necessary. Use
'LogLevel debug' to get a backtrace.
"LogLevel debug" didn't produce any more information.
Update:
It is definitely routing problem.
I could partially solve the problem by adding this:
map.connect 'login', :controller => 'login', :action => "login_page "
map.connect 'login/list_users', :controller => "login", :action => "list_users "
map.connect 'login/add_user', :controller => "login", :action => "add_user"
map.connect 'login/logout', :controller => "login", :action => "logout"
to the routes.rb and just first line is working.
So redirecting to the <app>/login or typing it directly gives login_page action from the login controller.
The remaining problem is that I still can't use any action directly like /login/list_users or even login/login_page.
Comment