Ruby is a beautiful language for writing views
A couple of months ago, I was made redundant from my job at Shopify. This was a huge surprise to me and my colleagues and especially my new manager (I had just moved from Privacy Engineering to the Ruby and Rails Infrastructure team).
But in a sense, it came at the perfect time. I’d been experimenting with an idea to build a new view framework and I’d made just enough progress on the prototype to know it had legs. With about four months runway, I decided to work on this full-time, at least while I figured out what to do next.
Before I get into the details, let me tell you more about the idea and where it came from.
I was frustrated by the view layer in Rails. I wanted to break my views into small, encapsulated units that were easy to use across the application and easy to test in isolation. I found ActionView partials were not particularly suitable for this task.
It was impossible to define an explicit interface for a partial — you can kind of do this now with magic comments, but it’s still pretty awkward.
Partials are leaky, you can access instance variables defined on the controller or other views, so it’s easy to make a partial dependent on being rendered in a specific context.
Adding any kind of logic to a partial is really awkward. You have to use ERB tags to switch between HTML and Ruby, and the Ruby you do write often feels like the kind of thing you’d only ship in the final hours of a Hackathon.
A few people had mentioned ViewComponent so I decided to try it out. I loved how you could define a Ruby class for each UI component to encapsulate relevant data, conditions and calculations in one place. But it felt awkward having to switch to a separate file / language for the template, so I started thinking about whether a template could just be another method on the component class.
It’s pretty easy, conceptually, to represent an HTML document in Ruby — method calls are the elements, keyword arguments are the attributes and blocks are the contents, unless the content is just text in which case the first positional argument can be the content instead.
If you’re familiar with HTML, I’m sure you can imagine what the following Ruby might be expected to produce.
def template
nav do
ul do
li { a "Home", href: "/" }
li { a "About", href: "/about" }
li { a "Contact", href: "/contact" }
end
end
end
So this was my dream: a view component abstraction where the templates are written in pure Ruby.
Over the next few weeks, not only did I manage to get it to work, but I discovered that all the wonderful refactoring tools — extracting classes and private methods, mixing in modules, class hierarchy, etc. — are equally applicable to views written in Ruby as they are to the rest of your app. Using Ruby also means no context switching between static markup and dynamic values. The developer experience is truly wonderful.
My framework is called Phlex, and in the two months since I was made redundant, I’ve got it to a place where I think the beta release is solid enough to use in production.
I’ll share more details over the next few weeks. In the meantime, if you’re interested in learning more about Phlex, you can check out the website www.phlex.fun and listen to an episode of Remote Ruby where I chat about the project with Andrew Mason.
—Joel