Setting Up a New Rails App

This guide walks you through standing up a brand-new Rails application using the philosophies and tooling that LocoMotion recommends: Docker for a stable development environment, Just for command running, HAML for templates, and TailwindCSS + DaisyUI for styling.

Skipped Docker?

This guide picks up where the Docker guide leaves off — every command below runs inside the dev container it builds. If you didn't mean to skip it, start there and come back. Skipping on purpose? Install Ruby, Node, and PostgreSQL on your machine and run each command directly.

Why Just?

We use Just as our command runner instead of Make. It provides a cleaner, more readable syntax for defining commands, better error handling, and is easier to maintain than complex Makefiles.

1. Creating the Rails App

Inside the development container, everything is set up and ready for you to install Rails. Change into the app directory (which is mapped to your local machine) and run rails new:

cd /home/app && rails new . --skip --database=postgresql --javascript=esbuild --css=tailwind
Versions & Databases

If you want something other than PostgreSQL or TailwindCSS, you can change that here — these are just our recommendations.

We also tend to recommend lagging slightly behind the latest Ruby version, as the newest release occasionally has trouble building the Rails project. You can change it in dev/Dockerfile via the FROM line at the top.

If you run into trouble with the rails new command, this resets the generated files so you can try again without losing your dev config:

rm -rf .dockerignore .git .gitattributes .gitignore .node-version .ruby-version Gemfile README.md Rakefile app bin config config.ru

2. Database Configuration

Open the newly created config/database.yml and add the following three lines under the default key so Rails can reach the Postgres container:

# config/database.yml (under the default: key)
host: db
username: postgres
password: password

Now uncomment the app section in your docker-compose.yml file and run just app to build and start the application. After a minute or two you should see Puma listening on port 3000, and you can visit http://localhost:3000 to view your running app!

Note

Once the container is built, you can run just app-fast to simply start the containers without rebuilding. This is much faster than a full build every time.

3. Using UUIDs by Default

We believe strongly in using UUIDs for primary keys to increase security and avoid potential scaling issues down the road. To enable this by default for all generated models, create the following initializer:

# config/initializers/generators.rb
Rails.application.config.generators do |generator|
  generator.orm :active_record, primary_key_type: :uuid
end

Optional 4. Install HAML

While you can use the default ERB templating system, we highly recommend HAML — it provides a much cleaner language for your template files. Add the gems to your Gemfile:

# Gemfile
gem "haml-rails", "~> 2.0"

# For development only (helps convert ERB to HAML)
group :development do
  gem "html2haml"
end

Open a Docker shell in the app container with just app-shell and run bundle to install the gems. Then point Tailwind at your HAML views by updating tailwind.config.js:

// tailwind.config.js
module.exports = {
  content: [
    './app/views/**/*.html.haml',
    // ...
  ]
}

Finally, convert any existing .erb files to .haml:

Warning

This deletes your ERB files, so make sure you have a backup or can easily do a git revert.

HAML_RAILS_DELETE_ERB=true rails haml:erb2haml

For a deeper dive into HAML syntax and conventions, see the HAML guide.

Optional 5. Install DaisyUI and/or LocoMotion

TailwindCSS is a utility-based CSS framework that lets you build components by composing utility classes. It is already installed via the rails new command above, and we highly recommend it for every project.

DaisyUI builds on top of Tailwind by providing ready-made component classes, so a button becomes as simple as %button.btn. And LocoMotion builds on top of DaisyUI, wrapping those classes in ready-made Rails components like daisy_button.

Installing LocoMotion? Follow the Install guide — it covers the gem, the npm package, and the exact CSS block to copy. You do not need to install DaisyUI separately; LocoMotion depends on it and pulls it in automatically.

Just want DaisyUI? Open an app shell with just app-shell and install the packages yourself:

yarn add tailwindcss @tailwindcss/cli daisyui

Then register the plugin at the top of your application.tailwind.css. With Tailwind 4, plugins are configured directly in the CSS file:

/* app/assets/stylesheets/application.tailwind.css */
@import "tailwindcss";
@plugin "daisyui";
Tailwind 4 Configuration

Tailwind 4 moves all plugin configuration into the CSS file. Do not add DaisyUI to tailwind.config.js — that file is now only used to declare content scan paths.

What loco.css handles for you

If you installed LocoMotion, the loco.css import from the Install guide quietly fixes several papercuts. You shouldn't need to think about these — dive in only if one of them surprises you:

Your classes always win (where:)

Components apply their visual defaults through the where: variant, which compiles to zero-specificity :where() rules — so any utility you pass via css: overrides a default without !important. More than a dozen components rely on it, which is why the import is required rather than optional.

Dark mode stays in sync (dark:)

The custom dark: variant responds to both the OS-level dark preference and a DaisyUI theme controller set to a dark theme, so manual theme switching and system preference agree.

Floating labels keep their placeholder (floating-sticky)

Add floating-sticky alongside floating-label (e.g. via label_wrapper_css:) to pin the label in its raised position while an empty field still shows its placeholder — DaisyUI normally collapses the label until the field is focused or has a value. The rule also keeps the label visible on disabled fields.

Tooltips reveal on keyboard focus

DaisyUI 5 only reveals a tooltip on focus when the focused element is a child of .tooltip, so tip: tooltips placed directly on a button or link show on hover but not when a keyboard user tabs to them. loco.css ships the missing rule:

/* @profoundry-us/loco_motion/loco.css */
/* Reveal `tip:`/`tooltip` tooltips on keyboard focus */
.tooltip:focus-visible:is([data-tip]:not([data-tip=""]), :has(.tooltip-content:not(:empty))) {
  &[data-tip]::before,
  &::after,
  & > .tooltip-content {
    opacity: 1;
    --tt-pos: 0rem;
  }
}

Prefer no custom CSS at all for tooltips? Wrap the element in the daisy_tooltip (aliased daisy_tip) component instead — the focusable element becomes a child of the .tooltip, so keyboard focus works through DaisyUI's own rule.

6. Try It Out!

With everything installed, let's confirm it all works. First, tell the Rails server to bind to all interfaces in your Procfile.dev:

# Procfile.dev
web: env RUBY_DEBUG_OPEN=true bin/rails server -b 0.0.0.0

Update your Dockerfile to start the app using Foreman:

Before
# Dockerfile
CMD ["rails", "server", "-b", "0.0.0.0"]
After
# Dockerfile
CMD ["./bin/dev"]

Since we are using Docker, it also helps to clear out stale PID files on boot. Add these lines to bin/setup, just above the lines that restart the application server:

# bin/setup
puts "\n== Removing old PID files =="
system! "rm -rf /home/app/tmp/pids/server.pid"

Restart with just app (a full rebuild is required because we changed the Dockerfile). Now wire up a quick test route and controller action:

# config/routes.rb
root "application#test"

# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  def test
    render html: "Test", layout: true
  end
end

And modify your layout's body to show some Tailwind styling (and, if you installed it, a DaisyUI button):

- # app/views/layouts/application.html.haml
%body
  .m-2.p-2.rounded.bg-red-400
    = yield

  - # If you installed DaisyUI, add this too:
  .btn
    Test Button

Visit http://localhost:3000 — you should see a red, rounded box with the word "Test", and a gray DaisyUI button that reacts when you hover and click it!

Clean Up

Once you are done playing around, undo these layout and routing changes so they do not cause confusion later.

Success!

You now have a fully-configured Rails app the LocoMotion way. Keep the momentum going with these guides:

Made with by Profoundry .
Copyright © 2023-2026 Profoundry LLC.
All rights reserved.