Search code examples
rubyauthenticationsinatra-activerecord

How to tell Sinatra to allow user connection after signup or login


I built a small Sinatra application that was working, but I added a confirm_password in the signup form and made changes in user_controller and broke something. Now, it is not letting the user login even after entering a valid username and password. It again takes them to login/signup page.

I tried debugging with binding.pry, so I know that it is assigning session[:user_id] to user.id, but I'm not sure why it keeps asking for user credentials.

This is my migration for the user:

class CreateUsers < ActiveRecord::Migration[5.1]
  def change
    create_table :users do |t|
      t.string :username
      t.string :password_digest
      t.string :email
      t.timestamps
    end
  end
end

This is my user model:

class User < ActiveRecord::Base

  has_secure_password

  has_many :tips
  has_many :languages, through: :tips

  validates_presence_of  :username, :email, :password_digest
  validates_uniqueness_of :username, presence: {message: "That username is already taken, please use another username."}
  validates_uniqueness_of :email, presence: {message: "That email is already associated to another account. Please use another email."}

  include Slugifiable::InstanceMethods
  extend Slugifiable::ClassMethods

end

This is my user_Controller:

class UserController < ApplicationController

  get '/signup' do
    if !logged_in?
      erb :'users/signup'
    else
      redirect to '/tips'
    end
  end

  post '/signup' do
    # binding.pry
    if params[:username] == "" || params[:password] == "" || params[:email] == "" || params[:confirm_password] == ""
      redirect to '/signup'
      # binding.pry
    elsif params[:password] != params[:confirm_password]
      erb :'users/password_error'
    else
      user = User.create(username: params[:username], password: params[:password], email: params[:email])
      session[:user_id] = user.id
      redirect to '/tips'
    end
  end

  get '/login' do
    if !logged_in?
      erb :'users/login'
    else
      redirect to '/tips'
    end
  end

  post '/login' do
    # binding.pry
    user = User.find_by(username: params[:username])
    if user && user.authenticate(params[:password])
      session[:user_id] = user.id
      redirect to "#{user.username}/tips"
    else
      redirect to '/signup'
    end
  end

  get '/logout' do
    if logged_in?
      session.clear
      # binding.pry
      redirect to '/login'
    else
      redirect to '/'
    end
  end

  get '/users/:slug' do
    if logged_in? && current_user.slug == params[:slug]
      @user = User.find_by_slug(params[:slug])
      erb :'/users/show'
    else
      redirect to '/tips'
    end
  end

end

I don't think my signup form is creating any issue, but for debugging purposes, here is my signup.erb form:

<h2 style="color: #66FFFF">Sign Up for the Coding Tips </h2></br> </br>
 <form action="/signup" method="POST">
   <p> Username:          <input type="text" name="username" ></p>
   <p> Email:             <input type="email" name="email"></p>
   <p> Password:          <input type="password" name="password"></p>
   <p> Confirm password:  <input type="password" name="confirm_password"></p></br></br>
   <input type="submit" value="Sign Up">
 </form>

I am sure I am using a valid username and password. I tried creating a couple of new usernames, it also saves them to the database, but it doesn't let anyone login.

These are my helper methods:

def logged_in?
      !!current_user
    end

    def current_user
      @current_user ||= User.find(session[:id]) if session[:id]
    end

Here is my tip_comtroller

class TipController < ApplicationController

    use Rack::Flash

    get '/:slug/tips' do
      @user = User.find_with_slug(params[:slug])
      if logged_in? && session[:user_id] == @user.id
          erb :'/users/tips'
      else
          redirect to "/login"
      end
    end

    get '/tips' do
      erb :'/tips/tips'
    end

    get '/tips/new' do
      if logged_in?
          erb :'/tips/new'
      else
          redirect "/login"
      end
    end

    post '/tips' do
      @tip = current_user.tips.create(content: params[:content])
      if @tip
          if params[:language][:name].nil? || params[:language][:name].empty?
            @tip.language_id = params[:tip][:language_id]
          else
            new_language = Language.create(name: params[:language][:name])
            @tip.language_id = new_language.id
          end
          @tip.save
          @user = @tip.user
          redirect to "/tips/#{@tip.id}"
      else
          redirect "/tips/new"
      end
    end

    get '/tips/:id' do
      @id = params[:id]
      if logged_in?
        @tip = Tip.find_by_id(params[:id])
        if [email protected]?
          erb :'/tips/show'
        else
          erb :'/tips/show_error'
        end
      else
          redirect "/login"
      end
    end

    get '/tips/:id/edit' do
      if logged_in?
          @tip = Tip.find_by_id(params[:id])
          if @tip.user.username == current_user.username
              erb :'/tips/edit'
          else
              erb :'/tips/edit_error'
          end
      else
          redirect "/login"
      end
    end

    patch '/tips/:id' do
      @tip = current_user.tips.find_by(params[:id])
      if  @tip
          @tip.update(:content => params[:content])
          if params[:language][:name].nil? || params[:language][:name].empty?
            @tip.language_id = params[:tip][:language_id]
          else
            new_language = Language.create(name: params[:language][:name])
            @tip.language_id = new_language.id
          end
          @user = @tip.user
          @tip.save
          # binding.pry
          redirect "/tips/#{@tip.id}"
      else
          redirect "/tips/#{@tip.id}/edit"
      end
    end

    get '/tips/:id/delete' do
      @tip = Tip.find_by_id(params[:id])
      if logged_in?
          if current_user == @tip.user
              @tip.destroy
              redirect '/tips'
          else
              erb :'tips/delete_error'
          end
      else
          redirect "/login"
      end
    end

    get '/tips/:id/cancel' do
      redirect "/tips/#{@tip.id}"
    end
end

Solution

  • Your logged_in function is using :id instead of :user_id:

    def logged_in?
      !!current_user
    end
    
    def current_user
      @current_user ||= User.find(session[:id]) if session[:id]
    end
    

    Try changing it to this:

    def logged_in?
      !!current_user
    end
    
    def current_user
      @current_user ||= User.find(session[:user_id]) if session[:user_id]
    end