Alkasai says:

Here is how i did it. This is the OLD code in application_controller.rb:


def  authorize
        unless  User.find_by_id(session[:user_id]) 
            session[:original_uri]  =  request.request_uri
            #flash[:notice]  =  "You're loged in as #{params[:name]}" 
            redirect_to  :controller  =>  'admin' ,  :action  =>  'login'
        end
    end

And this is the NEW code in application_controller.rb:


def  authorize
        if User.count == 0 
            if request.path_parameters[:controller] == 'users' and request.path_parameters[:action] == 'create'
                #do nothing. let the users controoler verify that everything is correct 
            elsif !(request.path_parameters[:controller] == 'users' and request.path_parameters[:action] == 'new')
                flash[:notice] = "Please create Admin User" 
                redirect_to :controller => 'users' , :action => 'new'                
            end
        elsif  !User.find_by_id(session[:user_id])
            session[:original_uri]  =  request.request_uri
            redirect_to  :controller  =>  'admin' ,  :action  =>  'login'
        end
    end

This should redirect all the pages to ’/users/new’ (except the ’/store’ of cause), when there are no users in DB. However, only page that is not redirected for some reason is ’/admin/login’. Anybody knows why?

unknown

This is a quick and dirty solution, just creates a user with the given credentials when no user exists in the database. In login_controller.rb:


def login
  session[:user_id] = nil

  if request.post?
    if User.count.zero?
      user = User.create(:name => params[:name],
                         :password => params[:password],
                         :password_confirmation => params[:password])
    else
      user = User.authenticate(params[:name], params[:password])
    end

    if user
      session[:user_id] = user.id
      uri = session[:original_uri]
      session[:original_uri] = nil
      redirect_to(uri || { :action => "index" })
    else
      flash[:notice] = "Invalid user/password combination" 
    end
  end
end

Cosmin Lehene:

This will pass over authorize method like a valid login as long as no users are created in the database and will flash a warning notice permanently. After the first user is created it will ask for credentials.

In application.rb change the authorize method:

def authorize
  unless User.find_by_id(session[:user_id]) or User.count == 0
    session[:original_uri] = request.request_uri
    flash[:notice] = "Please login" 
    redirect_to(:controller => "login", :action => "login")
  end

  if User.count == 0 
    flash[:notice] = "Please create the first user account" 
  end
end
end

Of course, in order to get the required behavior, you have to modify the login action in login_controller.rb also:


def login
  session[:user_id] = nil
  if User.count == 0 
    redirect_to(:action => "add_user")
  elsif 
  [...]

k9d says:

I followed Cosmin’s example except I wanted the user to be redirect to the page where they can create the first user account. To achieve this I modified def authorize in application.rb to look more like this


#...
if User.count == 0 
  flash[:notice] = "Please create the first user account" 
  redirect_to(:controller => "login", :action => "add_user")
end
#...

All is well except the before_filter in login_controller.rb doesn’t allow the un-authorized user to see add_user. Is there a way to work around this problem?

Also, a handy mysql command if you need to manually clear out the last user, to Delete a row(s) from a table>


DELETE from [table name] where [field name] = 'whatever';

Matt says:

To allow an unauthorised user to get to the add_user page, check the path_parameters of the request:

def authorize
  unless User.find_by_id(session[:user_id]) or User.count == 0
    session[:original_uri] = request.request_uri
    flash[:notice] = "Please log in." 
    redirect_to(:controller=>"login", :action=>"login")
  end
  if User.count == 0 
    if request.path_parameters[:action]=="add_user" and request.path_parameters[:controller]=="login" 
      #As we are already on our way to the add_user action, do nothing here.
    else
      flash[:notice] = "Please create an account." 
      redirect_to(:controller=>"login", :action=>"add_user")
    end
  end
end

jwat says:

Matt’s code worked for me. However, as good programming practice, it makes more sense to write the logic for zero user counts as so:


def authorize
        unless User.find_by_id(session[:user_id]) or User.count == 0
            session[:original_uri] = request.request_uri
            flash[:notice] = "Please log in." 
            redirect_to(:controller=>"login", :action=>"login")
        end
        if (User.count == 0 and request.path_parameters['action'] != "add_user")
                flash[:notice] = "Please create an account." 
                redirect_to(:controller=>"login", :action=>"add_user")
        end
end

I suppose you can check for the controller params as well, but I didn’t bother.

h3. Dimitris says: All you need to do is go to application.rb and change the check in the authorize method to:

    unless User.find_by_id(session[:user_id]) || User.count == 0
In this way, authorization is bypassed if there are no users in the DB. As soon as you create a user, you’re asked to login and everything works as before. h3. Valerie says: Nice solution, Dimitris! I also added a flash notice, as Cosmin mentioned.

  def authorize
    flash[:notice] = "Please create an admin user" if User.count == 0
    unless User.find_by_id(session[:user_id]) || User.count == 0
      session[:original_uri] = request.request_uri
      flash[:notice] = "Please log in" 
      redirect_to :controller => 'admin', :action => 'login'
    end
  end

Grazybom

Here is my simple solution: admin_controller.rb


  def login
    if request.post?
      user = User.authenticate(params[:name], params[:password])
      if user
        session[:user_id] = user.id
        uri = session[:original_uri]
        session[:original_uri] = nil
        redirect_to(uri || { :action => "index" })
      elsif User.count.zero?
        flash[:notice] = "Create your first administrator account. Please, logout after you have created your new account and login with your new credentials." 
        redirect_to(:controller => "users", :action => "new")  
      else
        flash.now[:notice] = "Invalid user/password combination" 
      end
    end
  end

and application.rb


  def authorize
    unless User.find_by_id(session[:user_id]) or User.count.zero?
      session[:original_uri] = request.request_uri
      flash[:notice] = "Please log in" 
      redirect_to :controller => 'admin', :action => 'login'
    end
  end

Even though, each action is available via get request untill the first account is created.

m1kee

I didn’t like how Grazybom’s solution allowed full access to the entire site as long as there wasn’t any user account created.
Here’s my solution:

app/controllers/application.rb


def authorize
  unless User.find_by_id(session[:user_id]) || User.count.zero?
    session[:original_uri] = request.request_uri
    flash[:notice] = "Please log in" 
    redirect_to(:controller => 'admin', :action => 'login')
  end

  if (User.count.zero?)
    if !(request.path_parameters[:controller] == 'users' and request.path_parameters[:action] == 'new')
      if !(request.path_parameters[:controller] == 'users' and request.path_parameters[:action] == 'create')
        redirect_to(:controller => 'admin', :action => 'login')
      end
    end
  end
end
#...

app/controllers/admin_controller.rb

class AdminController < ApplicationController
  def login
    if User.count.zero?
      redirect_to(:controller => 'users', :action => 'new')
    end
#...