Skip to content

Instantly share code, notes, and snippets.

@caseywatts
Last active May 21, 2025 15:28
Show Gist options
  • Save caseywatts/4c93bd267833ba33bf039311aba9817a to your computer and use it in GitHub Desktop.
Save caseywatts/4c93bd267833ba33bf039311aba9817a to your computer and use it in GitHub Desktop.
Auto-generating aasm-diagram from Rails models

How can we automate generation of AASM diagrams, so our documentation will always be up to date with our code?

This gist does two main things that the aasm-diagram repo doesn't do on its own as of today (May 2025):

  1. Finds all of the uses of aasm in our Rails models itself, so we don't have to list them out
  2. Updates a markdown file that embeds each of the AASM diagrams

When should we generate this?

rails-erd uses database migrations as the moment to auto-generate an ERD diagram, which makes a ton of sense! We didn't find a great hook to use for aasm diagrams, but we considered a few options:

  • In a pre-commit hook, like via lint-staged, anytime a file in models/ is changed?
  • In a database migration, just because it's frequent on our application? But AASM can change in the model without a DB change so it's not semantically correct
  • In CI?

Manually seems okay for us, for now.

Who did this work?

I contributed a bit of this, but most of this was done by a coworker who asked me to share this out.

aasm

We use aasm to define state machines in our models.

Courtesy of aasm-diagram, here are some diagrams of the state machines that we currently have:

Note

These diagrams do not automatically update when we change our state machines.

We will do our best to remember to run bin/rails aasm:diagrams when changing state machines.

If thse diagrams are outdated, please consider opening a small PR to update them.

# lib/tasks/aasm.rake
namespace :aasm do
# :nocov:
task diagrams: :environment do
require "aasm-diagram"
docs = Rails.root.join("aasm/README.md")
docs_content =
docs.read.lines.take_while { it.exclude?("<!-- SNIP -->") }.join
docs_content << "<!-- SNIP -->\n\n"
ApplicationRecord
.descendants
.select { it.include?(AASM) }
.sort_by(&:name)
.each do |klass|
output_dir = Rails.root.join("aasm")
output = output_dir.join("#{klass.name.underscore}.png")
AASMDiagram::Diagram.new(klass.new.aasm, output)
docs_content << <<~MSG
## #{klass.name}
![#{klass.name} state machine](#{output.basename})
MSG
end
docs.write(docs_content)
end
# :nocov:
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment