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