Project

perron

0.0
No release in over 3 years
Perron is a Rails-based static site generator that follows Rails conventions. It allows you to create content collections with markdown or ERB, configure SEO metadata, and build production-ready static sites while leveraging your existing Rails knowledge with familiar patterns and minimal configuration.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Runtime

>= 7.2.0
>= 0
>= 0
>= 0
 Project Readme

Perron

A Rails-based static site generator.

Sponsored By Rails Designer

Rails Designer

Getting started

Installation

Start by adding Perron:

bundle add perron

Then generate the initializer:

rails generate perron:install

This creates an initializer:

Perron.configure do |config|
  config.site_name = "Helptail"
end

Mode

Perron can operate in two modes, configured via config.mode. This allows you to build either a full static site or integrate pages into a dynamic Rails application.

Mode :standalone (default) :integrated
Use Case Full static site for hosts like Netlify/Vercel Add static pages to a live Rails app
Output output/ directory public/ directory
Asset Handling Via Perron Via Asset Pipeline

Collections

Perron is, just like Rails, designed with convention over configuration in mind. Content is stored in app/content/*/*.{erb,md,*} and backed by a class, located in app/models/content/ that inherits from Perron::Resource.

The controllers are located in app/controllers/content/. To make them available, create a route: resources :posts, module: :content, only: %w[index show].

Create content

bin/rails generate content Post

This will create the following files:

  • app/models/content/post.rb
  • app/controllers/content/posts_controller.rb
  • app/views/content/posts/index.html.erb
  • app/views/content/posts/show.html.erb
  • Adds route: resources :posts, module: :content, only: %w[index show]

Setting a root page

To set a root page, include Perron::Root in your Content::PagesController and add a app/content/pages/root.{md,erb,*} file. This is automatically added for you when you create a Page collection.

Markdown support

Perron supports markdown with the markdownify helper.

There are no markdown gems bundled by default, so you'll need to add one of these:

  • CommonMarker
  • Kramdown
  • Redcarpet
bundle add {commonmarker,kramdown,redcarpet}

HTML transformations

Perron can post-process the HTML generated from your Markdown content.

Usage

Apply transformations by passing an array of processor names or classes to the markdownify helper via the process option.

<%= markdownify @resource.content, process: %w[lazy_load_images syntax_highlight target_blank] %>

Available processors

The following processors are built-in and can be activated by passing their string name:

  • target_blank: Adds target="_blank" to all external links;
  • lazy_load_images: Adds loading="lazy" to all <img> tags.
  • syntax_highlight: Applies syntax highlighting to fenced code blocks (e.g., ```ruby). This requires adding the rouge gem to your Gemfile (bundle add rouge). You will also need to include a Rouge CSS theme for colors to appear.

Creating your own processors

You can create your own processor by defining a class that inherits from Perron::HtmlProcessor::Base and implements a process method. Then, pass the class constant directly in the process array.

# app/processors/add_nofollow_processor.rb
class AddNofollowProcessor < Perron::HtmlProcessor::Base
  def process
    @html.css("a[target=_blank]").each { it["rel"] = "nofollow" }
  end
end
<%= markdownify @resource.content, process: ["target_blank", AddNofollowProcessor] %>

Embed Ruby

Perron provides flexible options for embedding dynamic Ruby code in your content using ERB.

1. File extension

Any content file with a .erb extension (e.g., about.erb) will automatically have its content processed as ERB.

2. Frontmatter

You can enable ERB processing on a per-file basis, even for standard .md files, by adding erb: true to the file's frontmatter.

---
title: Dynamic Page
erb: true
---

This entire page will be processed by ERB.
The current time is: <%= Time.current.to_fs(:long_ordinal) %>.

3. erbify helper

For the most granular control, the erbify helper allows to process specific sections of a file as ERB. This is ideal for generating dynamic content like lists or tables from your resource's metadata, without needing to enable ERB for the entire file. The erbify helper can be used with a string or, more commonly, a block.

Example: Generating a list from frontmatter data in a standard .md file.

---
title: Features
features:
  - Rails based
  - SEO friendly
  - Markdown first
  - ERB support
---

Check out our amazing features:

<%= erbify do %>
  <ul>
    <% @resource.metadata.features.each do |feature| %>
      <li>
        <%= feature %>
      </li>
    <% end %>
  </ul>
<% end %>

Data files

Perron can consume structured data from YML, JSON, or CSV files, making them available within your templates. This is useful for populating features, team members, or any other repeated data structure.

Usage

To use a data file, instantiate Perron::Site.data with the basename of the file and iterate over the result.

<% Perron::Site.data.features.each do |feature| %>
  <h4><%= feature.name %></h4>
  <p><%= feature.description %></p>
<% end %>

File location and formats

By default, Perron looks up app/content/data/ for files with a .yml, .json, or .csv extension. For a features call, it would find features.yml, features.json, or features.csv. You can also provide a path to any data file, via Perron::Data.new("path/to/data.json").

Accessing data

The wrapper object provides flexible, read-only access to each record's attributes. Both dot notation and hash-like key access are supported.

feature.name
feature[:name]

Feeds

The feeds helper automatically generates HTML <link> tags for your site's RSS and JSON feeds.

Usage

In your layout (e.g., app/views/layouts/application.html.erb), add the helper to the <head> section:

<head><%= feeds %></head>

To render feeds for specific collections, such as posts:

<%= feeds only: %w[posts] %>

Similarly, you can exclude collections:

<%= feeds except: %w[pages] %>

Configuration

Feeds are configured within the Resource class corresponding to a collection:

# app/models/content/post.rb
class Content::Post < Perron::Resource
  configure do |config|
    config.feeds.rss.enabled = true
    # config.feeds.rss.path = "path-to-feed.xml"
    # config.feeds.rss.max_items = 25
    config.feeds.json.enabled = true
    # config.feeds.json.max_items = 15
    # config.feeds.json.path = "path-to-feed.json"
  end
end

Metatags

The meta_tags helper automatically generates SEO and social sharing meta tags for your pages.

Usage

In your layout (e.g., app/views/layouts/application.html.erb), add the helper to the <head> section:

<head><%= meta_tags %></head>

You can render specific subsets of tags:

<%= meta_tags only: %w[title description] %>

Or exclude certain tags:

<%= meta_tags except: %w[twitter_card twitter_image] %>

Priority

Values are determined with the following precedence, from highest to lowest:

1. Controller action

Define a @metadata instance variable in your controller:

class Content::PostsController < ApplicationController
  def index
    @metadata = {
      title: "All Blog Posts",
      description: "A collection of our articles."
    }
    @resources = Content::Post.all
  end
end

2. Page frontmatter

Add values to the YAML frontmatter in content files:

---
title: My Awesome Post
description: A deep dive into how meta tags work.
image: /assets/images/my-awesome-post.png
author: Kendall
---

Your content here…

3. Collection configuration

Set collection defaults in the resource model:

class Content::Post < Perron::Resource
  # …

  config.metadata.description = "Put your routine tasks on autopilot"
  config.metadata.author = "Helptail team"
end

4. Default values

Set site-wide defaults in the initializer:

Perron.configure do |config|
  # …

  config.metadata.description = "Put your routine tasks on autopilot"
  config.metadata.author = "Helptail team"
end

Related resources

The related_resources method allows to find and display a list of similar resources from the sme collection. Similarity is calculated using the TF-IDF algorithm on the content of each resource.

Basic usage

To get a list of the 5 most similar resources, call the method on any resource instance.

# app/views/content/posts/show.html.erb
@resource.related_resources

# Just the 3 most similar resources
@resource.related_resources(limit: 3)

XML sitemap

A sitemap is a XML file that lists all the pages of a website to help search engines discover and index content more efficiently, typically containing URLs, last modification dates, change frequency, and priority values.

Enable it with the following line in the Perron configuration:

Perron.configure do |config|
  # …
  config.sitemap.enabled = true
  # config.sitemap.priority = 0.8
  # config.sitemap.change_frequency = :monthly
  # …
end

Values can be overridden per collection…

# app/models/content/post.rb
class Content::Post < Perron::Resource
  configure do |config|
    config.sitemap.enabled = false
    config.sitemap.priority = 0.5
    config.sitemap.change_frequency = :weekly
  end
end

…or on a resource basis:

# app/content/posts/my-first-post.md
---
sitemap_priority: 0.25
sitemap_change_frequency: :daily
---

Building your static site

When in standalone mode and you're ready to generate your static site, run:

RAILS_ENV=production rails perron:build

This will create your static site in the configured output directory (output by default).

Sites using Perron

Sites that use Perron.

Standalone (as a SSG)

Integrated (part of a Rails app)

Contributing

This project uses Standard for formatting Ruby code. Please run be standardrb before submitting pull requests. Run tests with rails test.

License

Perron is released under the MIT License.