If you have Rails and Docker installed on your machine, running each of these demos is a matter of opening a terminal window, navigating to an empty directory, and copy/pasting a block of instructions into that window. Once started, navigate to http://localhost:3000/ to see the results. # Demo 1 - Minimal Rails provides a _smoke test_ for new applications that makes sure that you have your software configured correctly enough to serve a page. The following deploys that smoke test in production. Once done take a look at the `Dockerfile` file produced. ```bash rails new demo --minimal cd demo echo 'Rails.application.routes.draw { root "rails/welcome#index" }' > config/routes.rb bundle add dockerfile-rails --optimistic --group development bin/rails generate dockerfile docker buildx build . -t rails-demo docker run -p 3000:3000 -e RAILS_MASTER_KEY=$(cat config/master.key) --rm rails-demo ``` # Demo 2 - Neofetch Similar in spirit to the previous demo, but installs and runs Linux commands to show container status. ```bash rails new demo --minimal cd demo echo 'Rails.application.routes.draw { root "neofetch#get" }' > config/routes.rb cat << 'EOF' > app/controllers/neofetch_controller.rb require 'open3' class NeofetchController < ApplicationController def get Open3.pipeline_r('neofetch', 'ansi2html') do |out, threads| # adjust to a two column layout html = out.read .sub(/body \{/, "\\0display: grid; justify-items: center; " + "font-size: 2vw; grid-template-columns: auto auto; ") .sub(/<\/b>\n\s*/, "\n
")
        .gsub(/^\s+(<|---)/, '\1')

      render html: html.html_safe
    end
  end
end
EOF

bundle add dockerfile-rails --optimistic --group development
bin/rails generate dockerfile --add neofetch colorized-logs
docker buildx build . -t rails-demo
docker run -p 3000:3000 -e RAILS_MASTER_KEY=$(cat config/master.key) --rm rails-demo
```

Add `--load` to the `buildx` command if you want to save the image to local Docker.

# Demo 3 - Action Cable and Active Record

Real applications involve a network of services.  The following demo makes use of PostgreSQL and Redis to display a welcome screen with a live, updating, visitors counter. Once done, take a look at the `docker-compose.yml` file produced.

```bash
rails new demo --database postgresql
cd demo

bin/rails generate model Visitor counter:integer
bin/rails generate controller Visitors counter
bin/rails generate channel counter

cat << 'EOF' > app/controllers/visitors_controller.rb
class VisitorsController < ApplicationController
  def counter
    @visitor = Visitor.find_or_create_by(id: 1)
    @visitor.update! counter: @visitor.counter.to_i + 1
    @visitor.broadcast_replace_later_to 'counter',
      partial: 'visitors/counter'
  end
end
EOF

cat << 'EOF' > app/views/visitors/counter.html.erb
<%= turbo_stream_from 'counter' %>

<%= render "counter", visitor: @visitor %>
EOF cat << 'EOF' > app/views/visitors/_counter.html.erb <%= turbo_frame_tag(dom_id visitor) do %> <%= visitor.counter.to_i %> <% end %> EOF cat << 'EOF' > config/routes.rb Rails.application.routes.draw { root "visitors#counter" } EOF bundle add dockerfile-rails --optimistic --group development bin/rails generate dockerfile --compose export RAILS_MASTER_KEY=$(cat config/master.key) docker compose build docker compose up ``` # Demo 4 - API only This demo deploys a [Create React App](https://create-react-app.dev/) client and a Rails API-only server. Ruby and Rails version information is retrieved from the server and displayed below a spinning React logo. Note that the build process installs the node modules and ruby gems in parallel. ```bash rails new demo --api cd demo npx -y create-react-app client bin/rails generate controller Api versions cat << 'EOF' > app/controllers/api_controller.rb class ApiController < ApplicationController def versions render json: { ruby: RUBY_VERSION, rails: Rails::VERSION::STRING } end end EOF cat << 'EOF' > client/src/App.js import logo from './logo.svg'; import './App.css'; import React, { useState, useEffect } from 'react'; function App() { let [versions, setVersions] = useState('loading...'); useEffect(() => { fetch('api/versions') .then(response => response.json()) .then(versions => { setVersions(Object.entries(versions) .map(([name, version]) => `${name}: ${version}`).join(', ') ) }); }); return (
logo

{ versions }

); } export default App; EOF bundle add dockerfile-rails --optimistic --group development bin/rails generate dockerfile docker buildx build . -t rails-demo docker run -p 3000:3000 -e RAILS_MASTER_KEY=$(cat config/master.key) --rm rails-demo ``` # Demo 5 - Bunding Javascript (esbuild) While optional, bundling Javascript is a popular choice, and starting with Rails 7 there are three options: esbuild, rollup, and webpack. The the following demonstrates Rails 7 with esbuild: ```bash rails new demo --javascript esbuild cd demo yarn add react react-dom bin/rails generate controller Time index cat <<-"EOF" >> app/javascript/application.js import "./components/counter" EOF mkdir app/javascript/components cat <<-"EOF" > app/javascript/components/counter.jsx import React, { useState, useEffect, useRef } from 'react'; import { createRoot } from 'react-dom/client'; const Counter = ({ arg }) => { const [count, setCount] = useState(0); const countRef = useRef(count); countRef.current = count; useEffect(() => { const interval = setInterval(() => { setCount(countRef.current + 1); }, 1000); return () => clearInterval(interval); }, []); return
{`${arg} - counter = ${count}!`}
; }; document.addEventListener("DOMContentLoaded", () => { const container = document.getElementById("root"); const root = createRoot(container); root.render(); }); EOF cat <<-"EOF" > app/views/time/index.html.erb
React Logo
rails=<%= Rails::VERSION::STRING %>>
EOF cat <<-"EOF" > config/routes.rb Rails.application.routes.draw { root "time#index" } EOF bundle add dockerfile-rails --optimistic --group development bin/rails generate dockerfile docker buildx build . -t rails-demo docker run -p 3000:3000 -e RAILS_MASTER_KEY=$(cat config/master.key) --rm rails-demo ``` # Demo 6 - Grover / puppeteer / Chromium Uses Grover to produce a PDF of a web page. If you specify a `--platform` that contains `amd64`, chrome will be substituted for Chromium. `--platform` is required to access Chrome as Google doesn't supply Chrome binaries for Linux on ARM. ```bash rails new demo --minimal cd demo bundle add grover npm install puppeteer echo 'Rails.application.routes.draw { root "grover#pdf" }' > config/routes.rb cat << 'EOF' > app/controllers/grover_controller.rb class GroverController < ApplicationController def pdf grover = Grover.new('https://google.com', format: 'A4') send_data grover.to_pdf, filename: 'google.pdf', type: :pdf end end EOF bundle add dockerfile-rails --optimistic --group development bin/rails generate dockerfile docker buildx build . -t rails-demo docker run -p 3000:3000 -e RAILS_MASTER_KEY=$(cat config/master.key) --rm rails-demo ```