---
title: 'Easy Redesign in Rails: Run Old and New Side by Side with :variants'
author: Victor Cobos
tags: Rails, Design
published_at: '2025-08-25T08:01:00+02:00'
updated_at: '2025-08-25T11:11:28+02:00'
canonical_url: https://www.dotruby.com/articles/easy-redesign-in-rails-run-old-and-new-side-by-side-with-variants
---

# Easy Redesign in Rails: Run Old and New Side by Side with :variants

Rails variants are usually used to serve different views for devices — but you can use them for much more, like running a redesign side by side.

Redesigning a mature Rails app can feel like a minefield. You're still pushing hotfixes to production, QA needs to validate existing behavior, and stakeholders want to compare the old and new versions side by side. Imagine being able to render both designs on the same page — safely, in the same app, with minimal code overhead and in production.

That’s where `:variants` come in.

## What are Rails view :variants?

Most Rails developers know <a href="https://guides.rubyonrails.org/layouts_and_rendering.html#the-variants-option" target="_blank">`:variants`</a> as a way to serve different templates depending on device or context — like mobile vs. desktop. But the magic is that variants are format‑agnostic, so they can be used for any variation of a view.

Under the hood, when you use:

```ruby
render variants: [:mobile, :desktop]
```

Rails will look for templates in this order:

•	app/views/home/index.html+mobile.erb
•	app/views/home/index.html+desktop.erb
•	app/views/home/index.html.erb (fallback)

Perfect for device differences, sure — but it unlocks a more powerful use: **design rollouts**. You can add a `+redesign` version of your template, and Rails will choose it when `request.variant = :redesign` is set in your controller.

Because variants are supported throughout Rails, this approach works seamlessly with `layouts`, `partials`, `mailers`, and even `ViewComponent` templates. And since the logic for switching lives in a single place (setting `request.variant`), you avoid littering your views with scattered if statements or duplicating controller logic.

## Cookie-Free: Run Both Designs Side by Side

You might be tempted to toggle the redesign with a cookie, but for this use case I prefer using a simple URL parameter instead. By passing `?redesign=true` on every internal link, you can keep the old and new design running in separate browser windows or tabs at the same time. That's incredibly useful during a redesign process, because QA testers, designers, or developers can compare both versions side by side without clearing cookies or switching accounts.

Rails makes this easy with `default_url_options`. You can override it in your controller (or ApplicationController) to automatically add the `:redesign` parameter whenever it's present in the request:

```ruby
def default_url_options
  params[:redesign].present? ? {redesign: true} : {}
end
```

## How to Wire Variants into Your Rails App

Instead of duplicating the variant-switching code in every controller, a cleaner approach is to extract it into a concern. This way you can include it wherever you need the redesign toggle, and keep the logic consistent across your app.

For example, create a concern in `app/controllers/concerns/redesign.rb`:

```ruby
module Redesign
  extend ActiveSupport::Concern

  included do
    before_action :set_redesign_variant
  end

  private

  def default_url_options
    params[:redesign].present? ? {redesign: true} : {}
  end

  def set_redesign_variant
    if params[:redesign].present?
      request.variant = :redesign
    end
  end
end
```

You can then add this concern to any controller where you want redesign support: `include Redesign`.

With this setup, any request including `?redesign=true` will automatically render the `+redesign` templates for that controller's views. The best part is that the logic lives in one place, making it easy to maintain and adjust later (e.g., feature flags, user-specific rollouts).

## Full Support Across Rails Rendering Features

The great thing about variants is that they don’t just work with regular views. The same mechanism applies to **layouts**, **partials**, **mailers**, and even **[ViewComponent](https://viewcomponent.org)** templates. That means you can keep both old and new versions cleanly separated without sprinkling conditional logic all over your code. Wherever Rails looks for a template, it also looks for the variant — giving you full coverage for a redesign, end to end.

## Wrapping Up

The code examples in this post are meant as orientation — you'll likely need to adapt and refine them to fit your app. The key takeaway is that **Rails variants are a powerful tool for handling redesigns**. They let you keep old and new designs running in parallel, making it easier to test, compare, and roll out gradually.

In a real project, you’ll also want to think about **who can access the redesign**. Maybe you add a simple switcher in the UI, but only show it to specific users, or restrict it by office IPs. Feature flags and role checks are natural ways to manage that.

Finally, variants can even help you track your progress. By checking which views already have a +redesign template and which don’t, you can measure how much work is left before the old design can be retired.

Using `:variants` this way keeps your redesign process safe, transparent, and incremental — no more big-bang releases.

## Resources

* [Releasing a Redesign using Feature Flags and Rails Variants](https://therailsrunner.com/releasing-a-redesign-using-feature-flags-and-rails-variants/)
