Rails 8 Application Setup
Overview
Bootstrap a new Rails 8 application with production-ready defaults:
- •Rails 8 with Solid Queue, Solid Cache, Solid Cable
- •Built-in authentication (has_secure_password)
- •Multi-tenancy via Account scoping
- •Hotwire (Turbo + Stimulus)
- •Minitest + fixtures for testing
- •Tailwind CSS for styling
Quick Start
bash
rails new myapp --css tailwind --database sqlite3 cd myapp
Post-Generation Setup
1. Generate Authentication
bash
bin/rails generate authentication bin/rails db:migrate
This creates:
- •
Usermodel withemail_addressandpassword_digest - •
Sessionmodel with token-based sessions - •
Currentmodel (CurrentAttributes) - •
Authenticationconcern - •
SessionsController
2. Add Account Model (Multi-Tenancy)
bash
bin/rails generate model Account name:string bin/rails generate migration AddAccountToUsers account:references bin/rails db:migrate
ruby
# app/models/account.rb class Account < ApplicationRecord has_many :users, dependent: :destroy validates :name, presence: true end
ruby
# app/models/user.rb
class User < ApplicationRecord
has_secure_password
has_many :sessions, dependent: :destroy
belongs_to :account
normalizes :email_address, with: ->(e) { e.strip.downcase }
validates :email_address, presence: true,
uniqueness: true,
format: { with: URI::MailTo::EMAIL_REGEXP }
end
3. Add Current Account
ruby
# app/models/current.rb
class Current < ActiveSupport::CurrentAttributes
attribute :session
attribute :user_agent, :ip_address
delegate :user, to: :session, allow_nil: true
def account
user&.account
end
end
4. Configure Test Helper
ruby
# test/test_helper.rb
ENV["RAILS_ENV"] ||= "test"
require_relative "../config/environment"
require "rails/test_help"
module ActiveSupport
class TestCase
parallelize(workers: :number_of_processors)
fixtures :all
private
def sign_in(user)
session = user.sessions.create!
cookies.signed.permanent[:session_token] = {
value: session.token,
httponly: true
}
Current.session = session
end
def sign_out
Current.session&.destroy
cookies.delete(:session_token)
end
end
end
5. Create Fixtures
yaml
# test/fixtures/accounts.yml one: name: Acme Corp other: name: Other Corp
yaml
# test/fixtures/users.yml
one:
email_address: user@example.com
password_digest: <%= BCrypt::Password.create("password123") %>
account: one
admin:
email_address: admin@example.com
password_digest: <%= BCrypt::Password.create("password123") %>
account: one
other_account:
email_address: other@example.com
password_digest: <%= BCrypt::Password.create("password123") %>
account: other
yaml
# test/fixtures/sessions.yml one: user: one token: <%= SecureRandom.urlsafe_base64(32) %>
6. Configure Solid Queue
yaml
# config/queue.yml (already generated by Rails 8)
default: &default
dispatchers:
- polling_interval: 1
batch_size: 500
workers:
- queues: "*"
threads: 3
processes: 1
polling_interval: 0.1
ruby
# config/environments/production.rb
config.active_job.queue_adapter = :solid_queue
config.solid_queue.connects_to = { database: { writing: :queue } }
7. Configure Solid Cache
ruby
# config/environments/production.rb
config.cache_store = :solid_cache_store
config.solid_cache.connects_to = { database: { writing: :cache } }
8. Add Development Gems
ruby
# Gemfile group :development, :test do gem "debug", platforms: %i[mri windows], require: "debug/prelude" gem "brakeman", require: false gem "rubocop-rails-omakase", require: false gem "bullet" end
bash
bundle install
9. Configure Bullet (N+1 Detection)
ruby
# config/environments/development.rb config.after_initialize do Bullet.enable = true Bullet.alert = true Bullet.bullet_logger = true Bullet.console = true Bullet.rails_logger = true end # config/environments/test.rb config.after_initialize do Bullet.enable = true Bullet.raise = true end
10. Add Application Layout Defaults
erb
<%# app/views/layouts/application.html.erb %>
<!DOCTYPE html>
<html>
<head>
<title><%= content_for(:title) || "MyApp" %></title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %>
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
<%= javascript_importmap_tags %>
</head>
<body class="min-h-screen bg-white">
<div id="flash">
<% flash.each do |type, message| %>
<div class="flash flash-<%= type %>"><%= message %></div>
<% end %>
</div>
<main class="container mx-auto px-4 py-8">
<%= yield %>
</main>
</body>
</html>
Verification
Run the test suite to confirm everything is wired up:
bash
bin/rails test
Smoke Test
ruby
# test/models/user_test.rb
require "test_helper"
class UserTest < ActiveSupport::TestCase
test "fixture user is valid" do
user = users(:one)
assert user.valid?
end
test "requires email_address" do
user = User.new(password: "password123", account: accounts(:one))
assert_not user.valid?
assert user.errors[:email_address].any?
end
test "requires unique email_address" do
existing = users(:one)
user = User.new(
email_address: existing.email_address,
password: "password123",
account: accounts(:one)
)
assert_not user.valid?
assert user.errors[:email_address].any?
end
end
ruby
# test/models/account_test.rb
require "test_helper"
class AccountTest < ActiveSupport::TestCase
test "fixture account is valid" do
account = accounts(:one)
assert account.valid?
end
test "requires name" do
account = Account.new
assert_not account.valid?
assert account.errors[:name].any?
end
end
Directory Structure After Setup
code
app/
├── controllers/
│ ├── application_controller.rb
│ ├── concerns/
│ │ └── authentication.rb
│ └── sessions_controller.rb
├── models/
│ ├── account.rb
│ ├── current.rb
│ ├── session.rb
│ └── user.rb
├── views/
│ └── layouts/
│ └── application.html.erb
config/
├── database.yml
├── queue.yml
├── cable.yml
└── environments/
├── development.rb
├── production.rb
└── test.rb
test/
├── test_helper.rb
├── fixtures/
│ ├── accounts.yml
│ ├── users.yml
│ └── sessions.yml
└── models/
├── user_test.rb
└── account_test.rb
Rails 8 Defaults
Rails 8 ships with these defaults already configured:
- •Solid Queue - Database-backed Active Job backend (replaces Redis/Sidekiq)
- •Solid Cache - Database-backed cache store (replaces Redis/Memcached)
- •Solid Cable - Database-backed Action Cable adapter
- •Propshaft - Asset pipeline (replaces Sprockets)
- •Import Maps - JavaScript without bundling
- •Kamal - Deployment
- •Thruster - HTTP/2 proxy with asset caching
Checklist
- • Rails app generated
- • Authentication generated and migrated
- • Account model created (multi-tenancy)
- • Current model configured with account
- • Test helper with sign_in/sign_out
- • Fixtures created (accounts, users, sessions)
- • Solid Queue configured
- • Solid Cache configured
- • Bullet configured for N+1 detection
- • Smoke tests pass
- • All tests GREEN