Writing boilerplate code manually wastes time and introduces inconsistency. Rails generators automate the creation of models, controllers, migrations, tests, and entire CRUD scaffolds. Custom generators go further, encoding your team’s conventions into reusable templates.

What can Rails generators create?

Rails ships with generators for every common task:

# Model with attributes
rails generate model Product name:string price:decimal active:boolean

# Controller with actions
rails generate controller Products index show new create

# Full CRUD scaffold
rails generate scaffold Product name:string price:decimal description:text

# Migration
rails generate migration AddCategoryToProducts category:string

Each generator creates multiple files: the primary file, a test file, and any supporting files (routes, views, helpers).

Scaffold vs individual generators

GeneratorCreatesBest for
scaffoldModel, migration, controller, views, routes, testsRapid prototyping, admin panels
modelModel class, migration, test fileAdding a data layer without UI
controllerController, views, helper, testPages without a database model
migrationMigration file onlySchema changes to existing tables
resourceModel, controller, routes (no views)API endpoints

How do you build custom generators?

Rails’ generator system is extensible. Create generators that encode your project’s conventions:

rails generate generator service_object

This creates lib/generators/service_object/ with a template and generator class. Define what files get created:

# lib/generators/service_object/service_object_generator.rb
class ServiceObjectGenerator < Rails::Generators::NamedBase
  source_root File.expand_path("templates", __dir__)

  def create_service_file
    template "service.rb.tt", File.join("app/services", class_path, "#{file_name}.rb")
  end

  def create_test_file
    template "service_test.rb.tt", File.join("test/services", class_path, "#{file_name}_test.rb")
  end
end

The template file uses ERB:

# lib/generators/service_object/templates/service.rb.tt
class <%= class_name %>
  def initialize(params)
    @params = params
  end

  def call
    # Implementation here
  end

  private

  attr_reader :params
end

Now rails generate service_object ProcessPayment creates both the service and its test with your team’s conventions baked in.

Which code generation patterns save the most time?

API resource generation

For API-only apps, generate resources without views:

rails generate resource Api::V1::Product name:string price:decimal --no-assets --no-helper

This creates the model, namespaced controller, routes, and migration without frontend files.

Factory generation for tests

Pair generators with factory_bot to auto-create test factories:

# Custom generator that creates a factory alongside a model
def create_factory_file
  template "factory.rb.tt", File.join("spec/factories", "#{plural_file_name}.rb")
end

Serializer generation

For JSON APIs, generate serializers automatically:

rails generate serializer Product name price description

This pattern scales well. When every new model comes with a serializer, factory, and policy object by default, you eliminate an entire class of “forgot to create the supporting files” bugs.

How do you generate Ruby scripts outside Rails?

For standalone Ruby scripts, code generation patterns still apply. ERB templates work without Rails:

require 'erb'
require 'fileutils'

template = <<~TEMPLATE
  class <%= class_name %>
    def initialize(<%= attributes.join(', ') %>)
      <% attributes.each do |attr| %>
      @<%= attr %> = <%= attr %>
      <% end %>
    end

    <% attributes.each do |attr| %>
    attr_reader :<%= attr %>
    <% end %>
  end
TEMPLATE

class_name = "User"
attributes = ["name", "email", "role"]

result = ERB.new(template, trim_mode: '-').result(binding)
File.write("#{class_name.downcase}.rb", result)

For file operations, API clients, and database scripts, templated generation avoids repetitive typing and enforces consistent patterns.

Practical Implementation: The USEO Approach

At USEO, we maintain a library of custom generators across client projects. Here is what we have found most valuable:

Project-specific scaffold templates. We override Rails’ default scaffold templates in lib/templates/. Our versions include proper error handling in controllers, pagination in index actions, and policy checks for authorization. Running rails generate scaffold on a USEO project produces production-ready code, not a starting point that needs heavy modification.

Domain-driven generators. Beyond Rails’ built-in generators, we create generators for domain concepts: rails generate bounded_context Payments creates a module with its own models directory, service objects, event handlers, and tests. This enforces architectural boundaries that would otherwise drift over time.

Generator testing. We test our custom generators with RSpec. Each generator spec verifies that the correct files are created with the expected content. When Rails updates change generator internals, our tests catch the breakage before it reaches client projects.

Rake task generators for data migrations. We have a rails generate data_migration BackfillUserRoles generator that creates a timestamped Rake task with logging, dry-run support, and batch processing built in. Data migrations are a common source of production incidents when done ad-hoc. Generators enforce safety patterns.

One-command project bootstrap. New USEO projects start with a single script that runs our custom generators in sequence: authentication setup, base service objects, API versioning structure, error handling middleware, and CI configuration. A new Rails API project goes from rails new to deployable in under 10 minutes with all our conventions in place.

FAQs

What kind of code can Rails generators create?

Rails generators create models, controllers, migrations, views, serializers, mailers, jobs, and tests. Custom generators can produce any file your project needs: service objects, policy classes, form objects, decorators, or domain-specific modules. The generator system uses ERB templates, so any text-based file can be generated.

Should you use scaffold in production projects?

Scaffolds are excellent for prototyping and admin interfaces. For production features, customize scaffold templates to match your project’s patterns (error handling, authorization, pagination). Override the defaults in lib/templates/ so that scaffolded code meets your standards from the start.

How do custom generators improve team consistency?

Custom generators encode architectural decisions into executable templates. Instead of documenting “every service object should have a call method and tests,” the generator creates them that way automatically. New team members produce consistent code from day one. When conventions change, updating the generator propagates the change to all future generated code.