Modeling your public static pages as resources in Ruby on Rails

Modeling your public static pages as resources in Ruby on Rails
In: Ruby on Rails

So we checked 2 major ways already of creating public (more or less) static pages:

  1. brute force drop your HTML into the app/assets/public
  2. have custom actions in something like a PublicPagesController/StaticPagesController.

Now I wanted to look at another approach.

Originally, I saw this in David Copeland's book Sustainable Web Development with Ruby on Rails.

He suggests modeling public static pages as resources, like you would do with the dynamic pages, to keep things consistent and more sustainable. After all, the suggestion of the book and of Rails is to keep it REST and rather create resources than custom routes.

So, a very simple example would be for you to have a resource :privacy_policy, only [:show]. The icky thing with that is that while you are suggesting a single resource here, Rails controllers are not smart enough to acknowledge it, so you'd still need to call it from a PrivacyPoliciesController. But you most probably have just 1 policy 🤪

While we could live with that or work around it, we could still end up with a lot of stuff and tons of resources that would litter our app, like if we had a resource for each public documentation page or user AB experiment page that marketing is throwing at us.

So, in these cases, you might still want to go with our custom routes approach and namespace those pesky marketing and doc pages:

# routes.rb
namespace :marketing do
  get :ab_test_feature1
  # ...
  get :experiment_99
end

What got me inspired by this approach is that I steered myself into a better type of thinking. I went from having a public pages controller where I would throw in my public pages as custom routes:

class PublicPagesController < ApplicationController  
  def home  
    # TODO: Create a landing page for the root route.  
  end  
  
  def major_systems  
    @major_systems = MajorSystem.for_public_view.preload(:pegs)  
  end

  # ... more custom routes ...
end

To a resource each:

class Public::HomeController < ApplicationController
  def show
    # We'll show the view here.
  end
end

class Public::MajorSystemsController < ApplicationController  
  def index  
    @major_systems = MajorSystem.original.language(major_systems_params[:language_iso])  
  end  
  
  def show  
    @major_system = MajorSystem.find(major_system_params[:id])  
  end  
  
  private  
  
  def major_systems_params  
    params.permit(:language_iso)  
  end  
  
  def major_system_params  
    params.permit(:id)  
  end  
end

Just by thinking about resources, the public pages became more of a full showcase of my feature. Before that, I was trying to cram everything into one route (PublicPagesController#major_systems) and then somehow dynamically choose which system to display via JavaScript or Turbo. But now on one of the public feature pages, the users can see a list of features in their preferred language (chosen via dropdown). It reduced the number of dropdowns on the page from 2 to 1, thus simplifying the UX.

There's also a detail page that shows a given resource in more detail that was easy to integrate in the Rails way using Rails partials and co.

You'll also notice that my public "static" pages are not completely static, this is because I like to showcase some functionality in there with actual data, which makes them probably rather public dynamic pages 😬 But on the other hand, the data that I'm showing is fairly static, it just happens to come from the database ;))

Anyway, that's kind of a rough outline of the whole public static pages as a resource approach.

I don't think modeling your public pages as resources is widely used or documented anywhere, but I did like what it did in the end to my thinking, the code, and the final result for the user. Win-win-win.

Comments
More from RichStone Input Output
Great! You’ve successfully signed up.
Welcome back! You've successfully signed in.
You've successfully subscribed to RichStone Input Output.
Your link has expired.
Success! Check your email for magic link to sign-in.
Success! Your billing info has been updated.
Your billing was not updated.