DEV Community

Dane Dawson
Dane Dawson

Posted on

Checklist for HTTP Rails/React user auth setup - Rails backend setup checklist.

This article is written as a destilling of this video series by Edutechional. If this is your first time creating a user authentication with Rails and React I would highly recommend watching the 10 video series to understand what is going on. I also recommend any of other videos he offers, his way of explaining is straightforward and easy to understand. If, however, this isn't your first time setting up a back end cookie based user auth and you just want a nitty gritty checklist of an auth framework, you've come to the right place! I tried to grab every bit of code needed to get it working with minimal descriptions to streamline flow. Good luck.


-Create new app in Rails with a pstgresql database and create the database

rails new app_name --database=postgresql
rails db:create

-Get latest version of bcrypt in your gemfile as well as rack-cors. At the time of writing this article:

Gemfile

gem 'bcrypt', '~> 3.1', '>= 3.1.13'
gem 'rack-cors', :require => 'rack/cors'

-update gems with console command of preference, I use

bundle

create file app/config/intilizers/cors.rb

Rails.application.config.middleware.insert_before 0, Rack::Cors do
    #first origin is your API host address
    allow do
        origins "http://localhost:3000"
        resource "*", headers: :any, methods: [:get, :post, :put, :patch, :delete, :options, :head], credentials: true
    end
    #second origin is front end host address
    allow do
        origins "http://app_name.herokuapp.com"
        resource "*", headers: :any, methods: [:get, :post, :put, :patch, :delete, :options, :head], credentials: true
    end
end

create file app/config/intilizers/session_store.rb

#key is how you want it to be identified in cookies, domain is same as above in cors file
Rails.application.config.session_store :cookie_store, key: "_appname", domain: "app_name.herokuapp.com"

app/config/routes.rb

root to: "static#home"

create file app/controllers/static_controller.rb

class StaticController < ApplicationController
    def home
        render json: { status: "It's working"}
    end
end

************

Check point

************

You should be able to visit your backend host (My example is http://localhost:3000) and have it show the json string

{"status": "It's working"}

-Create your user model, it must have a password_digest attribute. I am also adding email for validation. Then migrate models.

rails g model User email password_digest
rails db:migrate

app/models/user.rb

class User < ApplicationRecord
    has_secure_password
    #sets email as required attribute for model creation
    validates_presence_of :email
    #validates unique emails
    validates_uniqueness_of :email
end

---Quick check---

If you did this correctly then you should be able to create a user in the Rails console and it should store a user model with an encrypted password_digest. User creation should look like this for encryption:

User.create(email: "email@address.com", password: "password", password_confirmation: "password")

app/config/routes.rb

Rails.application.routes.draw do
  resources :sessions, only: [:create]
  resources :registrations, only: [:create]
  root to: "static#home"
end

Create app/controllers/sessions_controller.rb

class SessionsController < ApplicationController
    def create
        user = User.find_by(email: params["user"]["email"]).try(:authenticate, params["user"]["password"])

        if user
            session[:user_id] = user.id
            render json: {
                status: :created,
                logged_in: true,
                user: user
            } 
        else
            render json: { status: 401 }
        end
    end
end

Create app/controllers/registrations_controller.rb

class RegistrationsController < ApplicationController
    def create
        user = user.create!(
            email: params['user']['email'],
            password: params['user']['password'],
            password_confirmation: params['user']['password_confirmation'],
        )

        if user
            sessions[:user_id] = user.id 
            render json{
                status: created,
                user: user
            }
        else
            render json: {status: 500}
        end
    end
end

app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
    skip_before_action :verify_authenticity_token
end

************

Check point

************

To test the current interactions, start the rails server and in another terminal interface do the following (user info should be the same as the user created at previous checkpoint). Use your hosting address.

curl --header "Content-Type: application/json" \
--request POST \
--data '{"user": {"email": "z@dev.com", "password": "asdf"}}' \
http://localhost:3000/sessions

You should get some message similar to

{"status":"created","logged_in":true,"user":{"id":1,"email":"z@dev.com","password_digest":"$2a$12$m9er4Bkndom7g5I85Ppj0Ob8EoPYkcw/gApT1ofEz2Ld3y4Eopbzy","created_at":"2020-04-26T02:15:57.844Z","updated_at":"2020-04-26T02:15:57.844Z"}}

app/config/routes.rb

Rails.application.routes.draw do
  resources :sessions, only: [:create]
  resources :registrations, only: [:create]
  resources :logout, to: "sessions#logout"
  get :logged_in, to: "sessions#logged_in"
  root to: "static#home"
end

Create app/controllers/concerns/current_user_concern.rb

module CurrentUserConcern 
    extend ActiveSupport::Concern

    included do
        before_action :set_current_user
    end

    def set_current_user
        if sessions[:user_id]
            @current_user = User.find(session[:user_id])
        end
    end
end

app/controllers/sessions_controller.rb

class SessionsController < ApplicationController
    include CurrentUserConcern

    def create
        #unchanged
    end

    def logged_in 
       if @current_user
            render json: {
                logged_in: true,
                user: @current_user
            }
        else
            render json: {
                logged_in: false
            }
       end
    end

    def logout
        reset_session
        render json: { status: 200, logged_out: true}
    end
end

app/config/initializers/session_store.rb

if Rails.env == "production"
    Rails.application.config.session_store :cookie_store, key: "_homesteadtogether", domain: "jdh-homesteadtogether.herokuapp.com"
else
    Rails.application.config.session_store :cookie_store, key: "_homesteadtogether",

Finished!

That should complete the backend of the api. I will try to compress this into more concise single page paragraphs in the future. Working on the front end walkthrough now.

Top comments (0)