Skip to main content

Command Palette

Search for a command to run...

Design Previews for Ruby on Rails

How to easily design in code and compare designs side by side in Ruby on Rails applications.

Updated
6 min read

You are iterating on a design. Maybe you are redesigning your dashboard. Maybe you are trying three different layouts for a landing page. Maybe Claude just gave you four variations of a pricing table and you need to pick one.

Here is the problem: every time you make a change, you overwrite the last version.

Designing directly in code has become incredibly fast with LLMs. You describe what you want, you get working HTML and CSS back in seconds. But the speed creates a new problem. You generate version one, tweak the prompt, generate version two, and now version one is gone. You want to compare them. You want to send both to your designer or PM and ask which one feels better. You want to open them side by side and squint at the differences.

Instead, you are copying files into _old suffixes, creating git branches for each variation, or pasting markup into a notes app just to preserve your options. This is friction that slows you down right when you should be moving fast.

What you really want is simple: a way to maintain multiple versions of the same view, switch between them instantly, and share any version with a URL.

ActionVersionPreview solves your Rails design version problems.

ActionVersionPreview: Multiple Designs, Zero Configuration

ActionVersionPreview is a Rails gem that lets you preview multiple versions of your UI simultaneously. Add it to your Gemfile:

gem "action_version_preview"

Run bundle install. That is it. No initializer. No configuration. No database migrations. No backend dependencies.

Just Name Your Files

The gem uses Rails' native view variants, which have a simple naming convention:

app/views/dashboard/show.html.erb           # default
app/views/dashboard/show.html+v2.erb        # variant :v2
app/views/dashboard/show.html+v3.erb        # variant :v3
app/views/dashboard/show.html+redesign.erb  # variant :redesign

The +variant suffix tells Rails this is an alternative template. ActionVersionPreview lets you switch between them with a URL parameter:

/dashboard           # renders show.html.erb
/dashboard?vv=v2     # renders show.html+v2.erb
/dashboard?vv=v3     # renders show.html+v3.erb

That is the entire interface. Create a file, add the suffix, visit the URL. No registration of variants. No config files. No enum definitions. Just files and URLs.

The Variant Switcher

Drop this helper in your layout:

<%= variant_switcher %>

A floating widget appears when the vv parameter is present. It auto-detects which variants exist for the current page by scanning your view directory. Click to switch between versions without editing the URL.

Side-by-Side Comparison

Open three browser tabs:

  • Tab 1: /dashboard

  • Tab 2: /dashboard?vv=v2

  • Tab 3: /dashboard?vv=v3

All three are logged in as you. All three show your real data. Arrange them side by side and compare instantly.

Share With a URL

Getting feedback is trivial:

Hey, can you look at https://staging.myapp.com/dashboard?vv=redesign
and tell me if the new nav makes sense?

Your teammate clicks the link, sees the variant, gives feedback. No setup required on their end.

Works Everywhere Rails Looks for Templates

Variants apply to layouts, partials, mailers, and ViewComponent templates. If you have:

app/views/shared/_header.html.erb
app/views/shared/_header.html+v2.erb

When rendering with the v2 variant active, Rails automatically uses _header.html+v2.erb. Your entire render tree respects the variant.

Helper Methods

These are available in controllers and views:

current_variant         # => :v2 or nil
detected_variants       # => ["v2", "v3", "redesign"]
variant_preview_active? # => true when ?vv param is present
can_preview_variants?   # => true if current user has access

Optional Configuration

The defaults work for most cases. If you need to customize:

# config/initializers/action_version_preview.rb
ActionVersionPreview.configure do |config|
  # Change the URL parameter (default: :vv)
  config.param_name = :variant

  # Control access (default: dev/test only)
  config.access_check = ->(controller) {
    Rails.env.development? ||
    Rails.env.test? ||
    controller.current_user&.admin?
  }
end

In production, restrict access to admins or staff so random users cannot access your experimental designs.

Why Not Feature Flags?

You might be thinking: I already have Flipper (or LaunchDarkly, or whatever). Why not use that?

Feature flags solve a different problem. They answer the question: "Which users should see this feature?" They are built for:

  • Percentage rollouts to production users

  • A/B testing with statistical significance

  • Gradual migrations where you need a kill switch

  • User-specific targeting based on attributes

This is not what you need when iterating on designs. You are not rolling out to users. You are not measuring conversion rates. You are trying to look at three versions and pick one.

Feature Flags (Flipper, etc.)View Variants (ActionVersionPreview)
Toggle features on/off for usersAccess all versions simultaneously
One version "live" at a timeSide-by-side comparison in multiple tabs
Percentage rollouts, A/B testingDesign iteration, feedback collection
Requires database or RedisZero dependencies
Configuration and targeting rulesJust file names and URLs

Feature flags add complexity you do not need for design work. You end up with conditional logic in your views:

<% if Flipper.enabled?(:new_dashboard, current_user) %>
  <!-- new design -->
<% else %>
  <!-- old design -->
<% end %>

This pollutes your templates with branching logic. With variants, each version is a clean, separate file. No conditionals. No flag checks. Just the design.

Use feature flags when you need controlled rollouts to real users. Use ActionVersionPreview when you need to compare options and collect feedback before choosing what to ship.

How It Works

The implementation is simple. When you visit /dashboard?vv=v2:

  1. A before_action checks for the vv parameter

  2. If present, it sets request.variant = :v2

  3. Rails' template resolver looks for show.html+v2.erb

  4. If found, it renders that. If not, it falls back to show.html.erb

The variant persists across navigation through default_url_options. Click a link on the page and the vv parameter carries forward. No cookies, no sessions, no database writes. Just URL parameters.

The switcher widget detects variants by globbing the view directory:

Dir.glob("app/views/dashboard/show.html+*.erb")
# => ["show.html+v2.erb", "show.html+v3.erb", "show.html+redesign.erb"]

Standard Rails variants like mobile, tablet, and phone are filtered out so they do not clutter your switcher.

Credits

This pattern builds on Rails' native view variants, which have been in the framework since Rails 4.1. The approach of using URL parameters for variant selection was inspired by these posts:

I extracted the variant-only approach into this gem because the feature flag complexity is unnecessary when all you want is to compare designs.

Conclusion

LLMs have made generating UI variations trivially easy. The bottleneck is no longer creating options. It is comparing them and getting feedback.

ActionVersionPreview removes that bottleneck. Create variant files, visit URLs, compare side by side. Share with your team using nothing but a link. Pick the winner, delete the losers, ship it.

No database. No Redis. No configuration. No view conditionals. Just Rails doing what Rails already knows how to do.

gem "action_version_preview"

Now go iterate.