Design Previews for Ruby on Rails
How to easily design in code and compare designs side by side in Ruby on Rails applications.
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:
/dashboardTab 2:
/dashboard?vv=v2Tab 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 users | Access all versions simultaneously |
| One version "live" at a time | Side-by-side comparison in multiple tabs |
| Percentage rollouts, A/B testing | Design iteration, feedback collection |
| Requires database or Redis | Zero dependencies |
| Configuration and targeting rules | Just 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:
A
before_actionchecks for thevvparameterIf present, it sets
request.variant = :v2Rails' template resolver looks for
show.html+v2.erbIf 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:
Easy Redesign in Rails: Run Old and New Side by Side with Variants by dotruby
Releasing a Redesign Using Feature Flags and Rails Variants by The Rails Runner, which documents how the Wrapbook team combined Flipper with URL parameter overrides during their UI rewrite
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.