My opinionated ruby on rails template
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

move to modules, plus some organization

+221 -150
+9 -8
.claude/commands/new-module.md
··· 3 3 argument-hint: <module-name> 4 4 --- 5 5 6 - Create a new boxcar module called `$ARGUMENTS.rb` in this Rails template project. 6 + Create a new boxcar module called `$ARGUMENTS.rb` in the `modules/` folder. 7 7 8 8 ## Context 9 9 - This is a Rails application template project (used with `rails new myapp -m template.rb`) 10 - - Modules are Ruby files that get applied via `apply_template('$ARGUMENTS')` in `template.rb` 10 + - Modules live in `modules/` and are applied via `apply_module('$ARGUMENTS')` in `template.rb` 11 11 - Each module should be self-contained and handle one feature/concern 12 12 13 13 ## Module Structure ··· 23 23 - `gem 'name'` - add gems 24 24 - `generate :model, 'Name field:type'` - run generators 25 25 - `file 'path', <<~RUBY ... RUBY` - create files 26 + - `initializer 'name.rb', <<~RUBY ... RUBY` - create initializers 26 27 - `inject_into_file`, `gsub_file` - modify files 27 28 - `route` - add routes 28 29 - `after_bundle do ... end` - run code after bundle install 29 30 30 31 ## Reference Files 31 32 Look at these existing modules for patterns: 32 - - @auth.rb - authentication module 33 - - @public_identifiable.rb - public IDs module 34 - - @tailwind.rb - Tailwind CSS module 35 - - @template.rb - main template entry point 33 + - @modules/auth.rb - authentication module 34 + - @modules/public_identifiable.rb - public IDs module 35 + - @modules/github.rb - simple GitHub workflow setup 36 + - @template.rb - main template entry point (orchestrator) 36 37 37 38 ## Task 38 39 1. Ask what the module should do if not clear from the name 39 - 2. Create the module file `$ARGUMENTS.rb` 40 - 3. Show how to add it to `template.rb` using `apply_template('$ARGUMENTS')` 40 + 2. Create the module file `modules/$ARGUMENTS.rb` 41 + 3. Show how to add it to `template.rb` using `apply_module('$ARGUMENTS')`
aasm.rb modules/aasm.rb
admin_routes.rb modules/admin_routes.rb
+5
analytics.rb modules/analytics.rb
··· 90 90 include Trackable 91 91 RUBY 92 92 93 + say ' Configuring ApplicationMailer for tracking...', :cyan 94 + inject_into_file 'app/mailers/application_mailer.rb', after: "class ApplicationMailer < ActionMailer::Base\n" do 95 + " has_history\n utm_params\n" 96 + end 97 + 93 98 say 'Ahoy analytics configured!', :green 94 99 say ' Track events: ahoy.track "Event Name", key: value', :cyan 95 100 say ' Email tracking enabled for opens and clicks', :cyan
auth.rb modules/auth.rb
blazer.rb modules/blazer.rb
console1984.rb modules/console1984.rb
database.rb modules/database.rb
flipper.rb modules/flipper.rb
friendly_id.rb modules/friendly_id.rb
health_checks.rb modules/health_checks.rb
kaminari.rb modules/kaminari.rb
mailkick.rb modules/mailkick.rb
metrics.rb modules/metrics.rb
+18
modules/base_gems.rb
··· 1 + # frozen_string_literal: true 2 + 3 + say 'Installing base gems...', :green 4 + 5 + gem 'jb' # Fast JSON templates 6 + gem 'awesome_print' # Pretty print objects 7 + gem 'faraday' # HTTP client 8 + 9 + gem 'dotenv-rails', groups: %i[development test] 10 + 11 + file '.env.development', '' 12 + 13 + # Remove default allow_browser restriction 14 + gsub_file 'app/controllers/application_controller.rb', 15 + /^\s*# Only allow modern browsers.*\n\s*allow_browser versions: :modern\n?/m, 16 + '' 17 + 18 + say 'Base gems installed!', :green
+33
modules/credentials.rb
··· 1 + # frozen_string_literal: true 2 + 3 + say 'Setting up credentials...', :green 4 + 5 + # Initialize credentials for each environment 6 + %w[development staging production].each do |env| 7 + say " Creating #{env} credentials...", :cyan 8 + run "EDITOR='echo' bin/rails credentials:edit --environment #{env}", abort_on_failure: false 9 + end 10 + 11 + # Create credentials example file 12 + file 'config/credentials.yml.example', <<~YAML 13 + # Credentials structure for all environments 14 + # Edit with: EDITOR=nano rails credentials:edit --environment <env> 15 + # 16 + # Generate keys in rails console: 17 + # Lockbox.generate_key 18 + # BlindIndex.generate_key 19 + # SecureRandom.hex(32) 20 + 21 + secret_key_base: # auto-generated 22 + 23 + lockbox: 24 + master_key: # Lockbox.generate_key 25 + 26 + blind_index: 27 + master_key: # BlindIndex.generate_key 28 + 29 + hashid: 30 + salt: # SecureRandom.hex(32) 31 + YAML 32 + 33 + say 'Credentials configured!', :green
+58
modules/development_tools.rb
··· 1 + # frozen_string_literal: true 2 + 3 + say 'Installing development tools...', :green 4 + 5 + # Development and debugging gems 6 + gem_group :development do 7 + gem 'pry-rails' 8 + gem 'bullet' 9 + gem 'query_count' 10 + gem 'actual_db_schema' 11 + gem 'annotaterb' 12 + gem 'letter_opener_web' 13 + end 14 + 15 + # Bullet configuration for N+1 query detection 16 + initializer 'bullet.rb', <<~RUBY 17 + # frozen_string_literal: true 18 + 19 + if defined?(Bullet) && Rails.env.development? 20 + Rails.application.configure do 21 + config.after_initialize do 22 + Bullet.enable = true 23 + Bullet.alert = false 24 + Bullet.bullet_logger = true 25 + Bullet.console = true 26 + Bullet.rails_logger = true 27 + Bullet.add_footer = true 28 + end 29 + end 30 + end 31 + RUBY 32 + 33 + # Letter Opener Web for email preview in development 34 + route <<~RUBY 35 + if Rails.env.development? 36 + mount LetterOpenerWeb::Engine, at: '/letter_opener' 37 + end 38 + RUBY 39 + 40 + inject_into_file 'config/environments/development.rb', before: /^end$/ do 41 + <<~RUBY 42 + 43 + # Use letter_opener for email delivery 44 + config.action_mailer.delivery_method = :letter_opener_web 45 + config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } 46 + RUBY 47 + end 48 + 49 + # Run generators after bundle 50 + after_bundle do 51 + say ' Running AnnotateRb installer...', :cyan 52 + rails_command 'generate annotate_rb:install' 53 + 54 + say ' Running Bullet installer...', :cyan 55 + rails_command 'generate bullet:install' 56 + end 57 + 58 + say 'Development tools installed!', :green
+27
modules/github.rb
··· 1 + # frozen_string_literal: true 2 + 3 + say 'Setting up GitHub workflows...', :green 4 + 5 + empty_directory '.github/workflows' 6 + 7 + # Migration index checker - ensures foreign keys are indexed 8 + file '.github/workflows/check-indexes.yml', <<~YAML 9 + name: Check Indexes 10 + on: 11 + pull_request: 12 + paths: 13 + - 'db/migrate/**.rb' 14 + 15 + jobs: 16 + check-indexes: 17 + runs-on: ubuntu-latest 18 + steps: 19 + - uses: actions/checkout@v4 20 + with: 21 + fetch-depth: 0 22 + 23 + - name: Check Migration Indexes 24 + uses: speedshop/ids_must_be_indexed@v1.2.1 25 + YAML 26 + 27 + say 'GitHub workflows configured!', :green
paper_trail.rb modules/paper_trail.rb
pg_search.rb modules/pg_search.rb
public_identifiable.rb modules/public_identifiable.rb
pundit.rb modules/pundit.rb
rails_performance.rb modules/rails_performance.rb
redis.rb modules/redis.rb
security.rb modules/security.rb
soft_delete.rb modules/soft_delete.rb
solid_queue.rb modules/solid_queue.rb
tailwind.rb modules/tailwind.rb
+71 -142
template.rb
··· 1 1 # frozen_string_literal: true 2 2 3 - say '🚞 boxcar - Rails starter kit', :cyan 3 + say '🚃 boxcar - Rails starter kit', :cyan 4 + say '' 4 5 5 - TEMPLATE_ROOT = if __FILE__.start_with?("http") 6 + # ═══════════════════════════════════════════════════════════════════════════════ 7 + # Template Configuration 8 + # ═══════════════════════════════════════════════════════════════════════════════ 9 + 10 + TEMPLATE_ROOT = if __FILE__.start_with?('http') 6 11 File.dirname(__FILE__) 7 12 else 8 13 __dir__ ··· 10 15 11 16 @post_install_tasks = [] 12 17 13 - def apply_template(template_name, tasks = []) 14 - apply File.join(TEMPLATE_ROOT, "#{template_name}.rb") 18 + def apply_module(name, tasks = []) 19 + apply File.join(TEMPLATE_ROOT, 'modules', "#{name}.rb") 15 20 @post_install_tasks.concat(tasks) 16 21 end 17 22 18 - gem 'jb' 19 - gem 'awesome_print' 20 - gem 'faraday' 21 - gem 'dotenv-rails', groups: %i[development test] 23 + # ═══════════════════════════════════════════════════════════════════════════════ 24 + # Base Setup 25 + # ═══════════════════════════════════════════════════════════════════════════════ 22 26 23 - gem_group :development do 24 - gem 'pry-rails' 25 - gem 'bullet' 26 - gem 'query_count' 27 - gem 'actual_db_schema' 28 - gem 'annotaterb' 29 - gem 'letter_opener_web' 30 - end 27 + apply_module('base_gems') 28 + apply_module('credentials') 29 + apply_module('development_tools') 30 + apply_module('github') 31 31 32 - file '.env.development', "" 32 + # ═══════════════════════════════════════════════════════════════════════════════ 33 + # Database & Infrastructure 34 + # ═══════════════════════════════════════════════════════════════════════════════ 33 35 34 - # Bullet configuration for N+1 query detection 35 - file 'config/initializers/bullet.rb', <<~RUBY 36 - # frozen_string_literal: true 36 + apply_module('database') 37 + apply_module('redis') 37 38 38 - if defined?(Bullet) && Rails.env.development? 39 - Rails.application.configure do 40 - config.after_initialize do 41 - Bullet.enable = true 42 - Bullet.alert = false 43 - Bullet.bullet_logger = true 44 - Bullet.console = true 45 - Bullet.rails_logger = true 46 - Bullet.add_footer = true 47 - end 48 - end 49 - end 50 - RUBY 39 + # ═══════════════════════════════════════════════════════════════════════════════ 40 + # Authentication & Authorization 41 + # ═══════════════════════════════════════════════════════════════════════════════ 51 42 52 - # Letter Opener Web for email preview in development 53 - route <<~RUBY 54 - if Rails.env.development? 55 - mount LetterOpenerWeb::Engine, at: '/letter_opener' 56 - end 57 - RUBY 43 + apply_module('public_identifiable') 44 + apply_module('auth', ['run `rails db:migrate`']) 45 + apply_module('pundit') 46 + apply_module('security') 58 47 59 - inject_into_file 'config/environments/development.rb', before: /^end$/ do 60 - <<~RUBY 48 + # ═══════════════════════════════════════════════════════════════════════════════ 49 + # Frontend 50 + # ═══════════════════════════════════════════════════════════════════════════════ 61 51 62 - # Use letter_opener for email delivery 63 - config.action_mailer.delivery_method = :letter_opener_web 64 - config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } 65 - RUBY 66 - end 52 + gem 'tailwindcss-rails' 53 + apply_module('tailwind') 67 54 68 - gsub_file 'app/controllers/application_controller.rb', 69 - /^\s*# Only allow modern browsers.*\n\s*allow_browser versions: :modern\n?/m, 70 - '' 55 + # ═══════════════════════════════════════════════════════════════════════════════ 56 + # Background Jobs & Feature Flags 57 + # ═══════════════════════════════════════════════════════════════════════════════ 71 58 72 - # Initialize credentials for each environment 73 - say 'Setting up credentials for all environments...', :green 74 - %w[development staging production].each do |env| 75 - say " Creating #{env} credentials...", :cyan 76 - run "EDITOR='echo' bin/rails credentials:edit --environment #{env}", abort_on_failure: false 77 - end 59 + apply_module('solid_queue') 60 + apply_module('flipper') 78 61 79 - # Create credentials example file 80 - file 'config/credentials.yml.example', <<~YAML 81 - # Credentials structure for all environments 82 - # Edit with: EDITOR=nano rails credentials:edit --environment <env> 83 - # 84 - # Generate keys in rails console: 85 - # Lockbox.generate_key 86 - # BlindIndex.generate_key 87 - # SecureRandom.hex(32) 62 + # ═══════════════════════════════════════════════════════════════════════════════ 63 + # Admin Dashboards 64 + # ═══════════════════════════════════════════════════════════════════════════════ 88 65 89 - secret_key_base: # auto-generated 90 - 91 - lockbox: 92 - master_key: # Lockbox.generate_key 93 - 94 - blind_index: 95 - master_key: # BlindIndex.generate_key 66 + apply_module('blazer') 67 + apply_module('rails_performance') 68 + apply_module('console1984') 96 69 97 - hashid: 98 - salt: # SecureRandom.hex(32) 99 - YAML 70 + # ═══════════════════════════════════════════════════════════════════════════════ 71 + # Monitoring & Analytics 72 + # ═══════════════════════════════════════════════════════════════════════════════ 100 73 101 - # Database configuration (must run early) 102 - apply_template('database') 103 - 104 - # Core modules (always installed) 105 - apply_template('public_identifiable') 106 - apply_template('auth', ['run `rails db:migrate`']) 107 - gem 'tailwindcss-rails' 108 - apply_template('tailwind') 109 - apply_template('pundit') 110 - apply_template('redis') 111 - apply_template('security') 112 - apply_template('flipper') 113 - apply_template('solid_queue') 114 - 115 - # Admin dashboards 116 - apply_template('blazer') 117 - apply_template('rails_performance') 118 - 119 - # Infrastructure 120 - apply_template('health_checks') 121 - apply_template('analytics') 122 - apply_template('console1984') 123 - 124 - # Common utilities 125 - apply_template('kaminari') 126 - apply_template('paper_trail') 127 - apply_template('soft_delete') 128 - apply_template('friendly_id') 129 - apply_template('pg_search') 130 - apply_template('aasm') 131 - apply_template('mailkick') 132 - apply_template('metrics') 133 - 134 - # Apply admin routes after all admin-related modules are loaded 135 - apply_template('admin_routes') 136 - 137 - # Create GitHub workflows 138 - say 'Creating GitHub workflows...', :green 139 - empty_directory '.github/workflows' 74 + apply_module('health_checks') 75 + apply_module('analytics') 76 + apply_module('metrics') 140 77 141 - file '.github/workflows/check-indexes.yml', <<~YAML 142 - name: Check Indexes 143 - on: 144 - pull_request: 145 - paths: 146 - - 'db/migrate/**.rb' 78 + # ═══════════════════════════════════════════════════════════════════════════════ 79 + # Data Management 80 + # ═══════════════════════════════════════════════════════════════════════════════ 147 81 148 - jobs: 149 - check-indexes: 150 - runs-on: ubuntu-latest 151 - steps: 152 - - uses: actions/checkout@v4 153 - with: 154 - fetch-depth: 0 82 + apply_module('paper_trail') 83 + apply_module('soft_delete') 84 + apply_module('friendly_id') 85 + apply_module('pg_search') 86 + apply_module('aasm') 155 87 156 - - name: Check Migration Indexes 157 - uses: speedshop/ids_must_be_indexed@v1.2.1 158 - YAML 88 + # ═══════════════════════════════════════════════════════════════════════════════ 89 + # Pagination & Email 90 + # ═══════════════════════════════════════════════════════════════════════════════ 159 91 160 - # Configure ApplicationMailer for tracking 161 - inject_into_file 'app/mailers/application_mailer.rb', after: "class ApplicationMailer < ActionMailer::Base\n" do 162 - " has_history\n utm_params\n" 163 - end 92 + apply_module('kaminari') 93 + apply_module('mailkick') 164 94 165 - # Run generators after bundle 166 - after_bundle do 167 - say 'Running development tool generators...', :green 95 + # ═══════════════════════════════════════════════════════════════════════════════ 96 + # Admin Routes (must be last - depends on all admin modules) 97 + # ═══════════════════════════════════════════════════════════════════════════════ 168 98 169 - say ' Running AnnotateRb installer...', :cyan 170 - rails_command 'generate annotate_rb:install' 99 + apply_module('admin_routes') 171 100 172 - say ' Running Bullet installer...', :cyan 173 - rails_command 'generate bullet:install' 174 - end 101 + # ═══════════════════════════════════════════════════════════════════════════════ 102 + # Finish 103 + # ═══════════════════════════════════════════════════════════════════════════════ 175 104 176 105 say '' 177 106 say '' ··· 184 113 say '' 185 114 end 186 115 187 - say 'Run `cd testapp && bin/dev` to start your app', :cyan 116 + say 'Run `cd #{app_name} && bin/dev` to start your app', :cyan 188 117 say ''