
In part one of this series, we walked through how to use Showcase in a Rails app.
It's now time to read some Ruby code written by experienced Rails developers. To do this without getting lost, we'll choose one feature of the showcase
engine and analyze how it works: rendering a preview of a component.
Let's get started!
About Showcase's Button Component Preview
If we visit http://localhost:3000/docs/showcase/previews/components/button
in the browser, we should see the complete documentation for a button component:

According to the showcase
documentation, this view is generated by the following code in the test/dummy
application:
<%# test/dummy/app/views/showcase/previews/components/_button.html.erb %> <% showcase.badge :partial, :component %> <% showcase.description "Button is our standard element for what to click on" %> <% showcase.sample "Basic" do %> <%= render "components/button", content: "Button content", mode: :small %> <% end %> <% showcase.sample "Large", description: "This is our larger button" do %> <%= render "components/button", content: "Button content", mode: :large %> <% end %> <% showcase.options do |o| %> <% o.required :content, "The content to output as the button text" %> <% o.optional :mode, "We support three modes", default: :small, options: %i[ small medium large ] %> <% end %>
But how does it work? That's what we are going to find out!
Rendering the Title, Badges, and Description
First, we'll modify our preview file to only render the title, badges, and description for now, making things easier to follow. Let's remove everything else from the preview file:
<%# test/dummy/app/views/showcase/previews/components/_button.html.erb %> <% showcase.badge :partial, :component %> <% showcase.description "Button is our standard element for what to click on" %>
If we refresh the page, we should now see a much simpler page:

To understand how such a view is generated, we can examine our Rails server logs, just as we would in a regular Rails application. If we refresh the button preview page, we should see the following logs in our terminal:
Started GET "/docs/showcase/previews/components/button" Processing by Showcase::PreviewsController#show as HTML Parameters: {"id" => "components/button"}
As we can see, the request is routed to the Showcase::PreviewsController#show
action, with the parameter id
set to "components/button"
. If we take a look at the routes, we can see that any route starting with previews/
will be routed to the Showcase::PreviewsController#show
action:
# config/routes.rb Showcase::Engine.routes.draw do get "previews/*id", to: "previews#show", as: :preview end
Showcase::PreviewsController#show
looks like this:
# app/controllers/showcase/previews_controller.rb class Showcase::PreviewsController < Showcase::EngineController def show @preview = Showcase::Path.new(params[:id]).preview_for view_context end end
As we can see, the show
action instantiates a new Showcase::Path
object with a "components/button"
extracted from the params
as an argument.
It then calls the preview_for
method on this instance, passing the view_context
as an argument. The result of this method call is assigned to the @preview
instance variable, which will be used later when rendering the view.
About view_context
If you are not familiar with view_context
, it is a Rails method that provides access to view helpers and other view-related methods. We will use it later to render HTML from models by calling view_context.render
.
Let's break down this code. The Showcase::Path
initializer looks like this:
# app/models/showcase/path.rb class Showcase::Path attr_reader :id, :segments, :basename def initialize(path) @id = path.split(".").first.delete_prefix("_").sub(/\/_/, "/") @basename = File.basename(@id) @segments = File.dirname(@id).split("/") end end
This means that Showcase::Path.new("components/button")
will create a new Showcase::Path
object with the following attributes:
Showcase::Path.new("components/button") # => @basename = "button" # => @id = "components/button" # => @segments = ["components"]
The controllers then call the Showcase::Path#preview_for
method on this instance, with the view_context
as an argument:
# app/models/showcase/path.rb class Showcase::Path def preview_for(view_context) Showcase::Preview.new(view_context, id: id, title: basename.titleize).tap(&:render_associated_partial) end end
This method first instantiates a new Showcase::Preview
object with the view_context
, the id
, and the basename
as arguments. In our case, the id
is "components/button"
and the basename
is "button"
.
About the Showcase::Preview
Initializer
Let's have a look at the Showcase::Preview
initializer:
# app/models/showcase/preview.rb class Showcase::Preview attr_reader :id, :badges, :samples def initialize(view_context, id:, title: nil) @view_context, @id = view_context, id @badges, @samples = [], [] title title end def title(content = nil) @title = content if content @title end end
As we can see, the initializer stores those arguments in instance variables. Here is the current state of our Showcase::Preview
instance:
Showcase::Preview.new(view_context, id: "components/button", title: "Button") # => @title = "Button" # => @id = "components/button" # => @samples = [] # => @badges = [] # => @view_context = The view context helper
The Showcase::Preview#render_associated_partial
method is then called on the Showcase::Preview
instance:
# app/models/showcase/preview.rb class Showcase::Preview def render_associated_partial @view_context.render "showcase/previews/#{id}", showcase: self nil end end
This method calls the render
method on the @view_context
. The render
method is the one we use every day in our Rails views to render a template or a partial and return some HTML.
In our case, the partial that we want to render is the showcase/previews/components/button
partial. The showcase
local is passed to the partial, which allows us to access our Showcase::Preview
instance in the partial:
<%# test/dummy/app/views/showcase/previews/components/_button.html.erb %> <% showcase.badge :partial, :component %> <% showcase.description "Button is our standard element for what to click on" %>
In the partial, we call two methods on the showcase
local variable. The first method is badge
, which adds badges to the preview:
# app/models/showcase/preview.rb class Showcase::Preview def badge(*badges) @badges.concat badges end end # => @badges = [:partial, :component]
The second method is description
, which sets the preview description:
# app/models/showcase/preview.rb class Showcase::Preview def description(content = nil, &block) @description = content || @view_context.capture(&block) if content || block_given? @description end end # => @description = "Button is our standard element for what to click on"
All of this code exists just to populate the @badges
, @description
, and @title
instance variables of our Showcase::Preview
instance.
This instance is returned by the Showcase::Path#preview_for
method and assigned to the @preview
instance variable in the Showcase::PreviewsController#show
action:
# app/controllers/showcase/previews_controller.rb class Showcase::PreviewsController < Showcase::EngineController def show @preview = Showcase::Path.new(params[:id]).preview_for view_context end end
Now, just like any controller, the Showcase::PreviewsController
will render the corresponding view. By convention, the view should be located at app/views/showcase/previews/show.html.erb
. To my surprise, it is located at app/views/showcase/engine/show.html.erb
, which isn't very conventional. However, it works because the Showcase::PreviewsController
inherits from Showcase::EngineController
.
If we have a look at the view, it contains the following code:
<%# app/views/showcase/engine/show.html.erb %> <%= render "showcase/engine/preview", preview: @preview %>
This view renders a partial called showcase/engine/preview
and passes our @preview
instance variable.
If we have a look at this view, we can see that it will render the title
, badges
, and description
of the preview in between the Tailwind CSS classes:
<%# app/views/showcase/engine/_preview.html.erb %> <% if preview.title %> <div class="..."> <h2 class="..."><%= preview.title %></h2> <% preview.badges.each do |badge| %> <span class="..."><%= badge.to_s.titleize %></span> <% end %> </div> <% end %> <% if preview.description %> <div class="..."><%= preview.description %></div> <% end %>
If we take a step back and reflect on the code architecture, it makes a lot of sense. The Showcase::Preview
model is responsible for storing the preview data, such as the title, badges, and description. The trick here is that this data is populated while rendering a preview template:
<%# test/dummy/app/views/showcase/previews/components/_button.html.erb %> <% showcase.badge :partial, :component %> <% showcase.description "Button is our standard element for what to click on" %>
As users of the showcase
engine, it feels like we are writing a view, but in reality, we are populating a model that will be used to render the final view. And look at how clean the interface is! We experience a great developer experience when using this gem!
Next Up: Rendering Samples using Showcase for Ruby on Rails
In this post, we've seen how the title, badges, and description of a preview are rendered in Showcase.
Now that we have a good understanding of how showcase
works, we can get our hands dirty with something a bit more meaty in the third and final part of our series: rendering samples!
See you next time!
Wondering what you can do next?
Finished this article? Here are a few more things you can do:
- Subscribe to our Ruby Magic newsletter and never miss an article again.
- Start monitoring your Ruby app with AppSignal.
- Share this article on social media
Most popular Ruby articles
What's New in Ruby on Rails 8
Let's explore everything that Rails 8 has to offer.
See moreMeasuring the Impact of Feature Flags in Ruby on Rails with AppSignal
We'll set up feature flags in a Solidus storefront using Flipper and AppSignal's custom metrics.
See moreFive Things to Avoid in Ruby
We'll dive into five common Ruby mistakes and see how we can combat them.
See more

Alexandre Ruban
Our guest author Alexandre is a freelance Ruby on Rails developer and author of the Turbo Rails tutorial. He enjoys writing about Ruby on Rails and reading open source code. He has contributed to Ruby on Rails, Hotwire, and Phlex.
All articles by Alexandre RubanBecome our next author!
AppSignal monitors your apps
AppSignal provides insights for Ruby, Rails, Elixir, Phoenix, Node.js, Express and many other frameworks and libraries. We are located in beautiful Amsterdam. We love stroopwafels. If you do too, let us know. We might send you some!
