Ruby on Rails 8 and Hotwire: Build a Password Manager
Build a modern full-stack Ruby on Rails app with a secure JSON API and a Google Chrome extension.
Course outcomes
What you'll learn
- Build a single-codebase Rails app that serves a web UI and a secure JSON API
- Create a secure JSON API with JWT authentication
- Use Hotwire (Turbo and Stimulus) to build an SPA-like experience
- Use Hotwire outside of a Ruby on Rails application
- Build a Google Chrome extension that consumes the Rails JSON API
- Autofill form data from the current site with the Chrome Extension API
- Apply Ruby on Rails best practices throughout
- And much more
class Entry < ApplicationRecord
belongs_to :user
validates :name, :username, :password, presence: true
validate :url_must_be_valid
encrypts :username, deterministic: true
encrypts :password
scope :search_name, ->(name) {
where("entries.name ILIKE ?", "%#{name}%") if name.present?
}
def self.search(name)
search_name(name).order(:name)
end
private
def url_must_be_valid
unless url.include?('http' || 'https')
errors.add(:url, 'must be valid')
end
end
end
class Api::V1::AuthController < Api::V1::ApiBaseController
skip_before_action :authenticate_token
def create
user = User.find_by(email: params[:email])
if user&.valid_password?(params[:password])
render json: {token: JsonWebToken.encode(sub: user.id)}, status: :ok
else
render json: {errors: ["Invalid email or password"]}, status: :unauthorized
end
end
end
import { Controller } from "@hotwired/stimulus"
import { checkIcon, clipboardIcon } from "../utils/icons"
class ClipboardController extends Controller {
async copy({ params: { content } }) {
try {
await navigator.clipboard.writeText(content)
this.element.innerHTML = checkIcon
setTimeout(() => {
this.element.innerHTML = clipboardIcon
}, 1000)
} catch(e) {
console.error('Failed to copy.')
}
}
}
export default ClipboardController
Real code, straight from the course.
Curriculum
Course content
- What We're Going to Build 8:32
- Source Code 0:45
- Development Setup 2:30
- Running Rails New and Starting our Server 9:23
- Pages Controller, Routing and Views 5:10
- View - Navbar Partial and Links 5:37
- Install Devise Gem 10:16
- Views - Style Devise Forms 18:15
- View - Logo Helper Method 3:39
- Stimulus - Flash Message and Form Error Initializer 16:25
- Model - Create a User and Check for a Session 8:42
- View - Style Account Page 8:27
- Model - Entry Model 6:04
- Routing - Entry Routing 1:52
- Controller and View - New Action 3:13
- View - New Entry Form 5:30
- Controller - Create Action 6:01
- Model - Entry Database Validations 8:58
- Model - Active Record Encryption 5:37
- View - Index Action for all Entries 4:01
- View and Controller - Show Action for a Single Entry 4:30
- Section Intro 2:21
- View - Prepare Index for SPA 6:41
- View - Dashboard Sidebar 4:08
- View - Dashboard Main 15:15
- Turbo Frames - View Single Entry in Main Dashboard 4:39
- Turbo Frames - Render New Entry form in Turbo Frame 8:28
- Turbo Streams - Create Action and View Updates 9:51
- Turbo Streams - Fix Flash Messages 4:43
- Turbo Streams - Delete Entry 13:56
- Database - Entry Seeds 1:54
- Turbo Frames - Inline Edit UI Pt. 1 7:31
- Turbo Frames - Inline Edit UI Pt. 2 11:21
- Turbo Streams - Inline Edit Update Action 7:29
- Model - Entry Search 9:25
- Turbo Streams - Auto Load Main Dashboard on Single Search Result 4:10
- Stimulus - Clear Search Results 9:33
- Stimulus - Copy to Clipboard 10:46
- Stimulus - Toggle Password Visibility 7:25
- Controller - Entries JSON API 4:49
- Controller - API Base Controller 3:00
- Controller - API Authentication 5:17
- JWT - Encode and Decode Token 7:39
- JWT - Decoding & Validating Tokens 7:05
- JWT - Exception Handling 6:18
- Section Intro 2:07
- Starter Template 5:47
- Setup and Upload to Chrome 4:56
- Base Sign in and Entries Frames 6:07
- Frame - Sign In Form 5:52
- Stimulus - Auth Controller 8:56
- Storage Service - setSessionStorage and getSessionStrorage 8:45
- Stimulus - Sign out and Navbar 6:31
- Stimulus - Entries Controller 8:58
- Service - Fetch Entries 8:19
- View - Entries Templates 7:30
- Stimulus - Entries Search 12:02
- Stimulus - Copy to Clipboard 2:50
- Stimulus - Toggle Password 2:21
- Navigate to Entry Sign In URL 5:48
- Auto Load Entry from activeTab URL 6:06
- sendMessage - Send credentials to contentScript 5:44
- onMessage Listener - Listen for Message and Fill in Credentials 4:58
- Utility Function - Input Selectors 5:31
- Deploy to Heroku --
- Deploy to Fly.io --
- Deploy to Render --
- Deploy to Chrome Web Store --
Reviews
What students say
“The Hotwire sections finally made Turbo and Stimulus click for me. Building the SPA without a JS framework was eye-opening.”
Alex P.
Backend Developer
“Loved that we built a real product end to end — the JWT API and the Chrome extension tied everything together.”
Priya S.
Full-stack Engineer
“Clear, practical, and modern. The best Rails 8 + Hotwire walkthrough I've found.”
Marcus L.
Rails Developer
FAQ
Frequently asked questions
Absolutely! This is course is hosted on Udemy so they handle everything payment related including refunds. Udemy offers a no-questions 30 day money back guarantee.
Instructor
Meet your instructor
Nick McNeany
Senior Software Engineer / Ruby on Rails instructor
I'm a software engineer with 10 years of professional experience in Healthcare, FinTech and Cybersecurity. In my current and past roles my primary focused has been Front-end development within a Ruby on Rails environment.
Aaron
★★★★★Amazing course and instructor.
André
★★★★★This was a really good course to get into Rails and to also understand how Hotwire works.
Oscar M.
★★★★★Great teaching, awesome content.
David Oliveira
★★★★★The explanations by the teacher are clear and direct, exactly what I'm looking for.