This is an opinionated handbook on how I migrated all my Rails apps off the cloud and into VPS.
This is how I manage real production loads for my Rails apps. It assumes:
- Rails 7+
- Ruby 3+
- PostgreSQL
- Ubuntu Server 24.04
- Capistrano, Puma, Nginx
{ | |
"workbench.colorTheme": "Aura Dark", | |
"workbench.iconTheme": "material-icon-theme", | |
"editor.fontFamily": "'Geist Mono', Menlo, Monaco, 'Courier New', monospace", | |
"apc.listRow": { | |
"height": 24, | |
"fontSize": 11 | |
}, | |
"window.titleBarStyle": "native", | |
"apc.font.family": "Geist Mono", |
This is an opinionated handbook on how I migrated all my Rails apps off the cloud and into VPS.
This is how I manage real production loads for my Rails apps. It assumes:
This guide will walk you through adding a ChatGPT-like messaging stream to your Ruby on Rails 7 app using ruby-openai, Rails 7, Hotwire, Turbostream, Sidekiq and Tailwind. All code included below!
Want more content like this, for free? Check out my free book, RailsAI!
import ApplicationController from './application_controller'; | |
import tippy from 'tippy.js'; | |
import 'tippy.js/dist/tippy.css'; | |
// Inspired by https://chrislabarge.com/posts/stimulus-popup/ | |
// NOTE: ApplicationController must have `this.element[this.identifier] = this;` in the connect() method. | |
/* | |
// Manually set content and trigger | |
// 'data-popup-trigger': :manual is optional. When no content is given, the controller isn't going to show a popup on mouseenter or click |
# mailboxes/concerns/mail_params.rb | |
module MailParams | |
extend ActiveSupport::Concern | |
def mail_params | |
attachments = build_attachments | |
body = build_rich_body(attachments) | |
{ subject: mail.subject, body: body, attachments: attachments.map { |a| a[:blob] } } | |
end |
source 'https://rubygems.org' | |
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails' | |
gem 'rails', '~> 6.0.0' | |
# Shorten boot time | |
gem 'bootsnap' | |
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder | |
gem 'jbuilder', github: 'rails/jbuilder' |
This is a Stimulus controller which will allow a Shoelace Form component to be processed and submitted by Turbo.
Just wrap your <sl-form>
control with a form tag:
<%= form_with url: "/test-submit" do %>
<sl-form data-controller="shoelace-form">
controls go here
</sl-form>
<% end %>
.spreadsheet--search.grid.grid-flow-col.grid-cols-auto.gap-0.auto-cols-fr.pl-1.pr-8.hidden{ data: { controller: "spreadsheet--search", action: "toggle-search@window->spreadsheet--search#toggleSearch" }} | |
.input.col-span-9.p-2 | |
%sl-input.w-full(placeholder="Search" size="small" clearable pill){ data: { target: "spreadsheet--search.input"}} | |
%sl-icon(name="search" slot="prefix") | |
%sl-dropdown(slot="suffix" placement="bottom-end" hoist){ data: { target: "spreadsheet--search.dropdown"}} | |
%sl-button(slot="trigger" caret type="text" size="small"){ data: { target: "spreadsheet--search.trigger"}} Highlight | |
%sl-menu | |
%sl-menu-item{ data: { target: "spreadsheet--search.higlight"}, checked: true} Highlight | |
%sl-menu-item{ data: { target: "spreadsheet--search.filter"}} Filter |
This is another piece of code I've extrapolated from a Ruby on Rails project I'm currently working on. The code implmenets social login with a RoR API-based application, targeted at API clients.
The setup does not involve any browser-redirects or sessions as you would have to use working with Omniauth.
Instead, what it does is takes an access_token generated on client-side SDKs, retireves user info from the access token
and creates a new user and Identity
in the database.
This setup works with native applications as described in the Google iOS Sign In Docs (see Authenticating with a backend server)
This is just some code I recently used in my development application in order to add token-based authentication for my api-only rails app. The api-client was to be consumed by a mobile application, so I needed an authentication solution that would keep the user logged in indefinetly and the only way to do this was either using refresh tokens or sliding sessions.
I also needed a way to both blacklist and whitelist tokens based on a unique identifier (jti)
Before trying it out DIY, I considered using: