Supercharge Your Bridgetown Site with Ruby Front Matter

Jared White Jared White on May 5, 2020

Starting in Bridgetown v0.13, you can now write real Ruby code directly in your Front Matter! 🤯 This feature is available for pages, posts, and other documents–as well as layouts for site-wide access to your Ruby return values.

This requires the environment variable BRIDGETOWN_RUBY_IN_FRONT_MATTER to be set to "true" in your development and deployment setups. Otherwise the code will not be executed and will be treated as a raw string.

Now you may be wondering, how is this even possible? Front Matter is in YAML format, and the only place you can write actual code is in a custom plugin, right? RIGHT??

Well…it just so happens that there’s this nifty bit of the YAML specification which allows for serialization and deserialization of objects. Normally that functionality is switched off in Bridgetown for security reasons. But we figured out a way to punch a hole through this security barrier to allow for a special type of string that represents Ruby code. It looks like this:

---
title: I'm a page
permalink: /ruby-demo
calculation: !ruby/string:Rb |
  [2 * 4, 5 + 2].min
---

Title: {{ page.title }}
Calc Result: {{ page.calculation }}

In this example, the value of the calculation variable is the return value of the Ruby code defined by the special string !ruby/string:Rb. The | symbol at the end just means all the indented code in the line(s) below are attached to that front matter variable.

The value printed out in the rendered page for the calculation will be 7 (since 7 is less than 8 and thus the minimum integer in the array). In fact, on this very page you’re reading, that number 7 is actually being generated by Ruby Front Matter, not hard-coded in this article! Thus you know the system works. ☺️

In Ruby Front Matter you can return any kind of value that is accessible from a Liquid template. So strings, numbers, arrays, hashes, integers: they all work. Even objects can be returned if they are implemented as a Liquid drop.

You can also access other Front Matter variables from within the Ruby code itself.

---
title_fragment: Title of a Page
title: !ruby/string:Rb |
  "This is the #{data["title_fragment"].sub("Title", "Name")}"
---

Now the page title will read: This is the Name of a Page

Use Cases for Ruby Front Matter

One particularly compelling use case for Ruby Front Matter is to load data in from a third-party source for inclusion on a page (typically in JSON format, but it could be anything really). Here’s an example of loading a file from a remote GitHub repository and parsing it to obtain useful information:

---
seo_tag_gem_version: !ruby/string:Rb |
  url = "https://raw.githubusercontent.com/bridgetownrb/bridgetown-seo-tag/master/lib/bridgetown-seo-tag/version.rb"
  result = Faraday.get(url).body
  result.match(/VERSION = "(.*?)"/)[1]
---

This will pull the current gem version of the master branch from bridgetown-seo-tag and output it via {{ page.seo_tag_gem_version }} (it’s 3.0.5).

Another example is a feature we include on this very website’s footer to show the average number of commits to the Bridgetown project on GitHub over the past month. (At the time this site was last built, that number is 21.)

Here’s the Ruby Front Matter we include in _layouts/default.html:

---
github_participation: !ruby/string:Rb |
  endpoint = "https://api.github.com/repos/bridgetownrb/bridgetown/stats/participation"

  conn = Faraday.new(
    url: endpoint,
    headers: {"Accept" => "application/vnd.github.v3+json"}
  )
  if ENV["BRIDGETOWN_GITHUB_TOKEN"]
    username, token = ENV["BRIDGETOWN_GITHUB_TOKEN"].split(":")
    conn.basic_auth(username, token)
  end
  json = JSON.parse(conn.get.body)
  json["all"][-4..].sum
---
<!doctype html>
…etc…

Then in our footer (or anywhere on the site), we simply add {{ layout.github_participation }} to output that value.

Caveats and Takeaways

If you need to write a lot of Ruby code, or write code that is easily customizable or reusable in multiple contexts, we still recommended you write a Bridgetown plugin—either in the plugins folder in your site repo or as a separate Gem-based plugin.

But if you just need to add a little bit of dynamic functionality to a page or a layout and like being able to see the code and content combined into a single file, Ruby Front Matter is a powerful and immensely flexible solution.

And remember, this isn’t a “lite” or stripped-down version of Ruby. This is 100% full Ruby. So you can process page or site data, instantiate objects, require gems, perform network requests, interact with the underlying filesystem, monkeypatch and metaprogram and do anything you’d ever need to do via Ruby.

For security reasons, please do not allow untrusted content into your repository to be executed in an unsafe environment (aka outside of a Docker container or similar). Just like with custom plugins, a malicious content contributor could potentially introduce harmful code into your site and thus any computer system used to build that site. Enable Ruby Front Matter only if you feel confident in your ability to control and monitor all on-going updates to repository files and data.

In summary, if you’re excited to give Ruby Front Matter a try, all you have to do is install Bridgetown v0.13 or later, set BRIDGETOWN_RUBY_IN_FRONT_MATTER to "true" in your development environment, and go to town (Bridge…town 😋). And be sure to share your sweet solutions on Twitter with the hashtag #SpinUpBridgetown to let the community know what you’ve built with Ruby Front Matter!

(Also learn which internal Bridgetown objects are made available to your Ruby code in the documentation here.

Previous
What's the Deal with Themes?

Next
PostCSS, Tailwind, Plugins…Oh My!