RepoPilotOpen in app →

zombocom/wicked

Use wicked to turn your controller into a wizard

Healthy

Healthy across all four use cases

Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • 29+ active contributors
  • MIT licensed
  • CI configured
Show 3 more →
  • Tests present
  • Stale — last commit 2y ago
  • Concentrated ownership — top contributor handles 61% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/zombocom/wicked)](https://repopilot.app/r/zombocom/wicked)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/zombocom/wicked on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: zombocom/wicked

Generated by RepoPilot · 2026-05-10 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/zombocom/wicked shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across all four use cases

  • 29+ active contributors
  • MIT licensed
  • CI configured
  • Tests present
  • ⚠ Stale — last commit 2y ago
  • ⚠ Concentrated ownership — top contributor handles 61% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live zombocom/wicked repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/zombocom/wicked.

What it runs against: a local clone of zombocom/wicked — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in zombocom/wicked | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch main exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 648 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>zombocom/wicked</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of zombocom/wicked. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/zombocom/wicked.git
#   cd wicked
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of zombocom/wicked and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "zombocom/wicked(\\.git)?\\b" \\
  && ok "origin remote is zombocom/wicked" \\
  || miss "origin remote is not zombocom/wicked (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
  && ok "default branch main exists" \\
  || miss "default branch main no longer exists"

# 4. Critical files exist
test -f "lib/wicked/wizard_controller.rb" \\
  && ok "lib/wicked/wizard_controller.rb" \\
  || miss "missing critical file: lib/wicked/wizard_controller.rb"
test -f "lib/wicked/controller/concerns/steps.rb" \\
  && ok "lib/wicked/controller/concerns/steps.rb" \\
  || miss "missing critical file: lib/wicked/controller/concerns/steps.rb"
test -f "lib/wicked/controller/concerns/render_redirect.rb" \\
  && ok "lib/wicked/controller/concerns/render_redirect.rb" \\
  || miss "missing critical file: lib/wicked/controller/concerns/render_redirect.rb"
test -f "lib/wicked/controller/concerns/action.rb" \\
  && ok "lib/wicked/controller/concerns/action.rb" \\
  || miss "missing critical file: lib/wicked/controller/concerns/action.rb"
test -f "lib/wicked/controller/concerns/path.rb" \\
  && ok "lib/wicked/controller/concerns/path.rb" \\
  || miss "missing critical file: lib/wicked/controller/concerns/path.rb"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 648 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~618d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/zombocom/wicked"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Wicked is a Rails gem that transforms standard controllers into multi-step wizard/form controllers using a RESTful state machine pattern. It manages step sequencing, validation, and navigation for sign-up flows, onboarding sequences, and any multi-step processes without requiring separate state machines or complex boilerplate. The core is ~47KB of Ruby that integrates via include Wicked::Wizard or inheritance from Wicked::WizardController. Modular Rails engine under lib/wicked: WizardController base class, controller Concerns (steps.rb, path.rb, action.rb, render_redirect.rb) composing the wizard logic, and a separate Wizard model for step management. Test/dummy contains realistic example controllers (bar_controller, updates_controller, nested/builder_controller) demonstrating the pattern. Uses standard Rails routing + convention.

👥Who it's for

Rails developers building post-signup flows, onboarding wizards, and multi-step forms who want a RESTful, convention-over-configuration approach without reaching for heavyweight state machine libraries. Typically used by full-stack Rails teams managing user journeys (password confirmation → profile setup → friend discovery).

🌱Maturity & risk

Production-ready and actively maintained. The repo shows a mature CI/CD setup (GitHub Actions, multi-Rails version appraisals from 5.2–7.1), test coverage across controllers, and documented changelog. Recent appraisals for Rails 7.1 and clean Gemfile/Rakefile indicate ongoing maintenance, though specific commit date would confirm recency.

Low risk for core functionality, but check for: single maintainer (schneems/zombocom) typical of long-standing gems, dependency on Rails version compatibility (mitigated by appraisals), and no visible breaking-change warnings in CHANGELOG. Main risk is legacy Rails projects not upgrading—ensure your Rails version matches gemfiles/rails_*.gemfile.

Active areas of work

Active maintenance for Rails 7.0+ compatibility (visible in gemfiles/rails_7.1.gemfile). CI workflow checking changelog entries and running tests across Ruby/Rails versions. No visible major breaking changes—focus is on keeping compatibility stable.

🚀Get running

git clone https://github.com/zombocom/wicked.git
cd wicked
bundle install
rake test

To test against a specific Rails version: BUNDLE_GEMFILE=gemfiles/rails_7.1.gemfile bundle install && bundle exec rake test.

Daily commands:

bundle exec rake test              # Run full test suite
cd test/dummy && rails server      # Run example app on localhost:3000

Wicked itself is a library, not a runnable app—use test/dummy/app or external repos like wicked_example for interactive demos.

🗺️Map of the codebase

  • lib/wicked/wizard_controller.rb — Main entry point that includes all wizard functionality; every wizard controller inherits from this class
  • lib/wicked/controller/concerns/steps.rb — Core step management logic; defines how wizards track, validate, and transition between steps
  • lib/wicked/controller/concerns/render_redirect.rb — Handles rendering and redirecting between wizard steps; critical for step navigation flow
  • lib/wicked/controller/concerns/action.rb — Action filtering and step-based routing logic; determines which step should be rendered
  • lib/wicked/controller/concerns/path.rb — Path generation and URL helpers for step navigation; enables RESTful step routing
  • lib/wicked/wizard.rb — Core Wizard class that manages step state and transitions; foundation for wizard behavior

🧩Components & responsibilities

  • WizardController (Rails ActionController) — Main class that controller inherits from; provides show/update actions and wizard-aware filters
    • Failure mode: If a controller does not inherit from WizardController, wizard methods are unavailable and step routing breaks
  • Steps Concern (Rails Concerns, Array operations) — Defines step array and validates current step against it; gates what steps are accessible
    • Failure mode: If steps array is not defined, controller raises error; if step validation fails, request is rejected
  • Action Concern (Rails before_action callbacks) — Filters incoming requests to ensure step parameter is valid before action execution
    • Failure mode: If action filter is bypassed, invalid steps could be rendered or updated
  • Render/Redirect Concern (Rails render/redirect_to) — Determines whether to render current step view or redirect to another step based on action response
    • Failure mode: If logic is incorrect, users may be stuck in infinite redirects or see wrong step templates
  • Path Concern (Rails routing, URL helpers) — Generates URLs and paths for step navigation; provides jump_to and step path helpers
    • Failure mode: If path generation is broken, step links and redirects will 404

🔀Data flow

  • BrowserRails Router — User navigates to /wizard/step_name or submits form to /wizard/step_name
  • Rails RouterWizardController#show/update — Routes request to appropriate action; :id parameter captures step name
  • WizardControllerSteps Concern — Controller checks if step name exists in @steps array
  • Steps ConcernAction Concern — Validates step and executes before_action filters
  • Action ConcernController Action — Allows show/update to execute if step is valid
  • Controller Action → `` — undefined

🛠️How to make changes

Create a new wizard controller

  1. Create a new controller inheriting from Wicked::WizardController (test/dummy/app/controllers/bar_controller.rb)
  2. Define steps array in the controller using steps :step1, :step2, :step3 (lib/wicked/controller/concerns/steps.rb)
  3. Create action handlers (show/update) for wizard logic (test/dummy/app/controllers/bar_controller.rb)
  4. Create view templates matching step names in views/{controller_name}/ directory (test/dummy/app/views/bar/first.html.erb)

Add custom step navigation logic

  1. Override jump_to() in your controller to validate step transitions (lib/wicked/controller/concerns/path.rb)
  2. Use finish_wizard_path to define where users redirect after final step (lib/wicked/controller/concerns/render_redirect.rb)
  3. Implement skip_step or redirect logic in your show/update actions (test/dummy/app/controllers/jump_controller.rb)

Add dynamic or conditional steps

  1. Override steps method to return computed step array based on conditions (test/dummy/app/controllers/dynamic_steps_controller.rb)
  2. Use skip_step in show action to conditionally skip steps (test/dummy/app/controllers/dynamic_different_steps_controller.rb)
  3. Verify step transitions in before_action callbacks (lib/wicked/controller/concerns/action.rb)

Add internationalization to wizard steps

  1. Include Wicked::Wizard::Translated mixin in your wizard controller (lib/wicked/wizard/translated.rb)
  2. Define translation keys for steps in config/locales/ (test/dummy/app/controllers/i18n_controller.rb)
  3. Call translated_step_name to get localized step names (lib/wicked/wizard/translated.rb)

🔧Why these technologies

  • Rails Engine — Provides seamless integration with existing Rails applications without requiring manual route configuration
  • Concerns/Mixins — Separates wizard functionality into composable modules (steps, action, path, render_redirect) for maintainability and reusability
  • State Machine Pattern — Manages step transitions and validation in a declarative, testable way without explicit conditional logic

⚖️Trade-offs already made

  • RESTful(ish) routing over fully RESTful

    • Why: Step-based wizards don't map cleanly to standard REST resources; the hybrid approach balances convention with flexibility
    • Consequence: Developers must understand step-as-state concept; routes like /wizard/:id/step_name are unconventional but more intuitive for wizards
  • Inheritance-based controller extension (WizardController) vs composition

    • Why: Inheritance makes it simple for developers to opt-in; single include point for all wizard functionality
    • Consequence: Controllers are tightly coupled to wizard framework; harder to mix wizards with other controller patterns
  • Server-side step validation over client-side routing

    • Why: Prevents invalid step transitions from client tampering; steps array acts as source of truth
    • Consequence: Each navigation requires a round-trip to server; cannot use full client-side navigation without re-implementing step logic

🚫Non-goals (don't propose these)

  • Does not persist wizard state to database; state exists only in request parameters and session
  • Does not provide client-side form validation or multi-field step forms (delegated to view layer)
  • Does not generate wizard UIs automatically; developers must create step templates
  • Does not handle payment processing or external integrations (application-specific responsibility)
  • Does not provide real-time collaboration or multi-user wizard state synchronization

🪤Traps & gotchas

Step name requirements: Steps must be defined as symbols in the controller (steps :step1, :step2)—string names won't work reliably with path helpers. Before/after hooks: Use skip_step in show action conditionally, not in filters (see skip_step usage in tests). Redirect-to-finish pattern: The gem doesn't auto-redirect on final step completion—you must explicitly redirect_to wizard_path(:finish) in update action. Rails routing: resources :wizard_name must match your controller name exactly (underscore case), or paths break. Nested wizards: test/dummy/app/controllers/nested/ shows nested resource routing requires custom path setup. Params persistence: Must manually carry model/context params across steps—no automatic session magic.

🏗️Architecture

💡Concepts to learn

  • RESTful State Machine — Wicked implements a constrained state machine (steps) as HTTP resources, allowing step sequencing without explicit StateMachine gems—understanding state flow and transitions is core to using the wizard pattern correctly
  • ActionController::Concerns (Rails Mixins) — Wicked is built entirely on Concerns (lib/wicked/controller/concerns/*.rb) to keep step logic, path generation, and rendering orthogonal—you need to understand how Concerns compose controller behavior
  • Implicit Resource Routing & Singular Resources — Wizard paths don't map to traditional REST CRUD; Wicked hijacks show/update to represent step navigation. Understanding singular resources (resource :wizard) vs resources :wizard is critical
  • Step Skipping / Conditional Flow — Real wizards skip steps based on user data. Wicked's skip_step method is a lightweight pattern; knowing when/how to call it in show actions prevents infinite loops
  • Session vs. Persistent State in Multi-Step Forms — Wizards must carry data across HTTP requests. Wicked does NOT auto-persist to session—you choose (session, model params, or IDs). This design decision avoids magic but requires explicit handling
  • I18n for Dynamic Step Labels — Wicked includes lib/wicked/wizard/translated.rb for i18n step names. Knowing how to wire i18n keys for step labels/progress bars is non-obvious and shown in test/dummy/app/controllers/i18n_controller.rb
  • Gem Appraisals / Dependency Versioning — Wicked maintains gemfiles/ for multiple Rails versions (5.2–7.1) tested in CI. Understanding appraisals and how to test compatibility across versions is critical for contributing to this multi-version gem
  • schneems/wicked_example — Official reference Rails app demonstrating real-world wizard patterns with Wicked; pairs directly with this gem
  • rails/rails — Wicked is a Rails-only gem; understanding ActionController::Concerns and routing is essential to using it
  • state-machines/state_machines-activerecord — Alternative approach for step-sequencing using explicit state machines on ActiveRecord models instead of wizard controllers
  • thoughtbot/administrate — Similar controller-level abstraction for building admin UIs with minimal boilerplate; complements Wicked for admin workflows
  • plataformatec/devise — Often paired with Wicked for post-signup onboarding flows (YouTube tutorials mention 'Devise Onboarding With Wicked')

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive test coverage for dynamic steps functionality

The repo has test controllers for dynamic steps (dynamic_steps_controller.rb and dynamic_different_steps_controller.rb) but there are no corresponding test files in test/controllers/ to verify this behavior. Dynamic step generation is a key feature that needs explicit test coverage to prevent regressions.

  • [ ] Create test/controllers/dynamic_steps_controller_test.rb with tests for step enumeration and transitions
  • [ ] Create test/controllers/dynamic_different_steps_controller_test.rb to test varying step sequences
  • [ ] Add tests validating that steps can be computed dynamically and that step position tracking works correctly
  • [ ] Verify edge cases like empty step lists and conditionally skipped steps

Add tests for nested wizard controllers

The dummy app includes test/dummy/app/controllers/nested/builder_controller.rb but there are no corresponding integration tests. Nested routing is a common Rails pattern that should be explicitly tested to ensure wicked works correctly with namespaced/nested controllers.

  • [ ] Create test/controllers/nested/builder_controller_test.rb
  • [ ] Add route configuration tests for nested wizard controllers
  • [ ] Test that step navigation works correctly with nested routes (e.g., /nested/builder/step/first)
  • [ ] Verify that rendering and redirection work properly in nested contexts

Add internationalization (i18n) test coverage

The repo has an i18n_controller with corresponding views (test/dummy/app/views/i18n/) and lib/wicked/wizard/translated.rb exists, but there's no test/controllers/i18n_controller_test.rb. I18n support appears to be a feature but lacks verification tests.

  • [ ] Create test/controllers/i18n_controller_test.rb with tests for translated step names
  • [ ] Add tests verifying that step translations are properly loaded and rendered
  • [ ] Test fallback behavior when translations are missing
  • [ ] Verify integration with lib/wicked/wizard/translated.rb functionality

🌿Good first issues

  • Add integration test for Rails 7.1 Zeitwerk autoloading with nested wizard controllers. Currently test/controllers/ lacks a case covering test/dummy/app/controllers/nested/builder_controller.rb end-to-end.: Zeitwerk changes autoloading behavior; nested controllers in lib/wicked may have subtle constant resolution bugs.: test/controllers/nested_integration_test.rb (new file)
  • Document the difference between include Wicked::Wizard and inherit Wicked::WizardController in the README and add a decision matrix. Currently README shows both but doesn't explain trade-offs.: New users get confused about which pattern to pick; clarifying controller composition vs inheritance helps onboarding.: README.md section after 'How' example, or new PATTERNS.md doc
  • Add validation error handling example test. test/controllers/ has happy-path tests (bar_controller_test, updates_controller_test) but no case showing how to re-render a step with form errors on validation failure.: Real wizards validate and reject updates; the gem needs a clear, testable pattern for error handling.: test/controllers/validation_error_controller_test.rb (new) + test/dummy/app/controllers/validation_error_controller.rb (new)

Top contributors

Click to expand
  • @schneems — 61 commits
  • @deepakmahakale — 7 commits
  • [@Matt Connolly](https://github.com/Matt Connolly) — 4 commits
  • @michael-garland — 2 commits
  • [@Nicholas Rutherford](https://github.com/Nicholas Rutherford) — 2 commits

📝Recent commits

Click to expand
  • 2e7114d — Add rails 7.1 to the test matrix (#302) (deepakmahakale)
  • 5e44548 — Run CI on a recurring schedule (#300) (cmason)
  • 7037c81 — Merge pull request #296 from petergoldstein/feature/adds_ruby_3_2_to_ci (deepakmahakale)
  • 5be6b3c — Adds Ruby 3.2 to the CI matrix. (petergoldstein)
  • 439b39f — v2.0.0 (deepakmahakale)
  • d360aaa — Return 422 - :unprocessable_entity when form submissions fails (#294) (deepakmahakale)
  • a46ffb8 — Add rails 7.0 to CI (#293) (deepakmahakale)
  • 0ab3cb5 — Add link to deanin video to readme (#292) (written-fresh)
  • 98034a2 — Add CI badge to README [changelog skip] [ci skip] (#289) (deepakmahakale)
  • dd2b3f3 — FIXES #287 - Add GitHub CI (#288) (deepakmahakale)

🔒Security observations

The wicked gem codebase appears to be a well-structured Rails wizard controller library with no obvious critical vulnerabilities detected in the available code. However, a complete security assessment cannot be performed without analyzing the actual Gemfile dependencies and full engine configuration. The main security concerns are: (1) inability to audit dependencies due to missing package file content, (2) lack of visible security header configuration, and (3) general CSRF token handling documentation for wizard forms. The gem's core functionality for step-by-step wizards should inherently benefit from Rails' built-in security features (CSRF protection, parameter filtering, SQL injection prevention via ORM). Recommend running bundle audit and security linters (brakeman) as part of CI/CD pipeline.

  • Medium · Missing Dependency Information — Gemfile, Appraisals, gemfiles/. The dependency/package file content is not provided. This prevents analysis of known vulnerable dependencies in the gemfile or other package managers. Unable to verify if outdated or vulnerable gems are being used. Fix: Provide the contents of Gemfile, Gemfile.lock, and gemfiles/* files. Run 'bundle audit' regularly to check for known vulnerabilities in dependencies.
  • Low · No Security Headers Configuration Visible — lib/wicked/engine.rb, test/dummy/app/controllers/application_controller.rb. No visible security header configuration (e.g., Content-Security-Policy, X-Frame-Options, X-Content-Type-Options) in the application files analyzed. The Rails engine configuration may lack security middleware setup. Fix: Configure security headers in the engine initializers and application controllers. Use gems like 'secure_headers' or manually set headers in ApplicationController using before_action filters.
  • Low · Limited CSRF Protection Visibility — lib/wicked/wizard_controller.rb, lib/wicked/controller/concerns/. While Rails provides CSRF protection by default, the gem's wizard controller implementation should explicitly document CSRF token handling across multi-step forms. Fix: Document CSRF token requirements for wizard views. Ensure all forms in wizard steps include CSRF tokens via Rails helpers (form_for, form_with).
  • Low · Test Data Not Segregated from Production Code — test/dummy/. Test controllers and dummy app are included in the repository root structure. While this is common for gems, ensure test fixtures don't contain sensitive data that could be exposed. Fix: Review test fixtures and dummy app data to ensure no credentials, API keys, or sensitive information are stored. Use environment variables for test configurations.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · zombocom/wicked — RepoPilot