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)