Alchemy CMS: great for managing websites integrated with Ruby on Rails

July 13, 2017 · Chris Peters

After learning Ruby on Rails, I played around a little with a few of the open source content management system options available, and one in particular stood out for what I typically need: Alchemy CMS.

Alchemy CMS

After learning Ruby on Rails, I played around a little with a few of the open source content management system options available, and one in particular stood out for what I typically need: Alchemy CMS.

I was happy to learn that Alchemy CMS installs as a Rails engine, meaning that you can integrate it into your existing Rails application and use it alongside the Rails features that you know and love.

Here’s a little tour of Alchemy and some of the features that I’ve found to be useful in building websites for small- and medium-sized organizations.

Key feature: keep the integrity of your design and layout with elements

Why not just install WordPress, Chris? Like 250% of the web runs on WordPress anyway, amirite?

The most dreaded part of WordPress as a CMS for websites is the single giant text editor per page. I hate nothing more than fixing a page layout wrecked by a content author who messed up some HTML in the WordPress Editor of Doom™. I know that there are advanced ways around this with custom fields, widgets, short codes, etc., but then you end up trying to force the content author to understand minutiae that they likely won’t remember 2 months later when they need to change something real, outside the scope of your demo.

Alchemy comes to the rescue with elements

An element in Alchemy CMS lets the web designer define a block of content comprised of different types of content (called essences: see the chemistry theme emerging yet?).

Let’s say that you have a heavily-styled content element, all rocked out with media queries and assumptions about the right-sized image. Rather than leaving behind a nested div structure for a future author to mess around with, you configure an element in config/alchemy/elements.yml with the content expected:

- name: call_to_action
hint: 'Call to action with headline, description, button, and secondary action.'
contents:
- name: headline
type: EssenceText
- name: description
type: EssenceRichtext
- name: button_link
type: EssenceLink
hint: Where to link the button.
- name: button_icon
type: EssenceText
hint: Icon to use within button. See www.fontawesome.io for a list of icons. Refer to the icon name without the "fa-" in front of it.
- name: button_text
type: EssenceText
- name: secondary
type: EssenceRichtext
hint: Secondary call to action. Place phone number in bold formatting.
view raw elements.yml hosted with ❤ by GitHub

After running rails g alchemy:elements --skip, you can edit app/views/alchemy/elements/_call_to_action_view.html.erb to define the HTML structure for the content, force image sizes, etc.

Your code may end up looking something like this:

<%- cache(element) do -%>
<%= element_view_for(element) do |el| -%>
<div class="cta">
<h3 class="cta-heading">
<%= el.render :headline %>
</h3>
<%= el.render :description %>
<div class="cta-actions">
<div class="cta-primary">
<%= link_to el.ingredient(:button_link), class: 'button cta-button' do %>
<%= fa_icon(el.ingredient(:button_icon)) if el.ingredient(:button_icon).present? %>
<%= el.render :button_text %>
<% end %>
</div>
<div class="cta-secondary">
<%= el.render :secondary %>
</div>
</div>
</div>
<%- end -%>
<%- end -%>

I really like this style because it encourages modular design. I usually end up with a matching Sass file somewhere like app/assets/stylesheets/modules/_ctas.scss.

I’ve found that I need to create some “general-purpose” elements for each site like title, rich_text, image, video, lead, button, etc. That’s probably the topic of a separate post. More of us should be sharing these sorts of details with the rest of the community.

Content editing experience with elements

The content author can then add one or many elements to any page, formatted exactly how you want. It ends up looking something like this in the Alchemy admin:

Editing an element in Alchemy CMS shows the produced content in-context and allows editing the content off to the side.

The overall editing experience reminds me of the increasingly popular Craft CMS, with the page content visible in context and content editing controls off to the side.

Notice the little question mark bubbles next to elements in the editor:

Hint bubbles with question marks appear next to fields defined with a hint in Alchemy CMS.

Those are hints that are revealed on hover, populated from the elements.yml example earlier in this post. You can help your content authors by providing explanations for elements and fields that may need some extra consideration. I find this to be a very nice touch, requiring a minimal amount of extra effort while authoring the elements.yml file.

Other features that make Alchemy worth trying out

Elements really are the flagship feature of Alchemy CMS in my mind, but here are a few other niceties.

Page layouts

Each page created in Alchemy CMS must have a defined page layout. Of course, the layouts that you create will depend on the requirements of the site. I typically create layouts for home, one_column, two_column, subpage, and narrow, give or take others.

The nice things about layouts:

  • You can define which elements are allowed in each layout. Have an element that’s only meant to be used on the home page? Only list it in the home layout.
  • Each layout can have one or many cells. These are basically different regions that elements can be added to. You can get granular and restrict which elements are allowed to be added to each cell.
  • You can indicate that a layout must be unique, i.e., it can only be used for one page. (There can only be one home page!)
  • Each layout can be configured to auto-generate new content items based on elements that you list. That way an editor can be presented with a title to fill in as a starter on each page, for example.

Here is a quick sample page_layouts.yml file for you to glance at:

- name: home
unique: true
elements:
- home_hero
- location_search_box
- lead
- rich_text
- image
- definition_list
- cta
cells:
- hero
- main
- sidebar
- name: single_column
elements:
- title
- lead
- rich_text
- image
- video
- button
- definition_list
autogenerate:
- title
- name: two_column
elements:
- title
- lead
- rich_text
- image
- video
- button
- definition_list
- event_sidebar
- contact_form
cells:
- heading
- sidebar

Powerful image processing

Alchemy ships with the Dragonfly gem, a nice API and configuration point for transforming and storing images. When you utilize this, you enter a nice scenario where content authors can upload a “master image” that can be reused and transformed in one or many places within the content.

As a quick example, you can do things like this to resize images to display thumbnail versions with a forced image format, etc.:

<%- cache(element) do -%>
<%= element_view_for(element, class: 'product-listing') do |el| -%>
<%# Force thumbail to be rendered at 372px height, and HTML tag to force height to 186px
# for higher DPI goodness. %>
<%= image_tag el.ingredient(:thumbnail).url(size: 'x372', format: 'jpg'), height: 186,
style: 'height: 186px;', class: 'product-listing-thumb' %>
<%- end -%>
<%- end -%>

Nestable elements

OK, one more thing about elements. You can have nestable elements: elements within elements. Let’s say I wanted to create my own definition list element, which most WYSIWYG editors generally don’t do so well at providing.

I could define something like this in elements.yml:

- name: definition_list
nestable_elements:
- definition_title
- definition
- name: definition_title
contents:
- name: title
type: EssenceText
- name: definition
contents:
- name: definition
type: EssenceText # Or EssenceRichText, depending on what you want to do.

Then I would define very simple views for the nested definition_title and definition elements:

<%- cache(element) do -%>
<%= element_view_for(element, tag: :dl) do |el| -%>
<% element.nested_elements.available.each do |nested_element| %>
<%= render_element(nested_element) %>
<% end %>
<%- end -%>
<%- end ->

<%- cache(element) do -%>
<%= element_view_for(element, tag: :dt) do |el| -%>
<%= el.render :title %>
<%- end -%>
<%- end -%>

<%- cache(element) do -%>
<%= element_view_for(element, tag: :dd) do |el| -%>
<%= el.render :definition %>
<%- end -%>
<%- end -%>

As you can see, I customized the tag used to contain each element (which defaults to div). You can also customize other things like the class attribute.

This then provides a nice UI for adding, removing, and drag-and-drop sorting child definition_title and definition elements within the parent definition_list:

Alchemy CMS provides a nice UI for adding nested elements to parent elements.

Rails workflow

I’ve mentioned this before, but I think it’s worth repeating. With Alchemy CMS, you can have a content management system sitting alongside a full-blown Rails application with its own controllers, models, etc.

That means that you can use other gems, the built-in Asset Pipeline (or soon the Webpack stuff in Rails 5.1), built-in caching strategies, integrate special objects in your elements (or even custom essences), etc.

The key is really in where you mount the Alchemy engine in config/routes.rb. Typically, your routes.rb file will end up looking like this:

Rails.application.routes.draw do
devise_for :users
# Your own custom logic is listed first.
resources :products
get :events, to: 'events#index'
namespace :system do
resources :products
end
# Alchemy takes it from here for URLs that don't match anything listed above.
# Keep in mind that Alchemy's admin is mounted at the `/admin` folder though.
mount Alchemy::Engine => '/'
end
view raw routes.rb hosted with ❤ by GitHub

Read more about Alchemy’s architecture.

Caveats, limitations, and bad news

Of course, no content management solution is going to be perfect. They all have their own strengths and weaknesses. Here are some of the negative things that I’ve noticed.

Documentation

In my opinion, the documentation is good enough to get started and gain a moderate understanding of how to build a solution with Alchemy. Unfortunately, it kind of ends there.

Because this is open source, you’re probably not surprised. Because it’s open source, maybe we should all be helping out with that (myself included).

No good way to reuse content

When you add a content item to a page, there is no real good way of sharing it with other pages. So if you have the same block of text on 15 different pages, you need to edit each content item individually.

It’s niche

The team behind Alchemy is great, but there isn’t that large of a community behind it, especially when you compare it to the popular open source PHP CMSes.

However, I’ve been able to use that to my advantage at times. Whenever I’ve needed help, the developers of Alchemy have been very eager to answer questions or even fix bugs. The Slack channel is especially useful for having direct access to the developers.

This is somewhat of a non-point because the overall Rails community is very large. Oftentimes, you can find a Ruby gem that does most of what a similar WordPress plugin would do anyway. However, you’ll end up needing to train content authors on how to use the system because there aren’t any completed manuals for them as of this writing.

The concept of “navigation” doesn’t provide the flexibility that I’d like to see

A page in Alchemy has a few options:

Alchemy CMS page properties dialog

By checking that “visible in navigation” check box, you have the ability to use some helpers provided by Alchemy CMS to build out a nested menu structure for the site. Really cool!

However, you are forcing that page to include a nested URL structure. That’s usually fine. (In this case, the URL of the page will be /products/widget-plus, which I like.)

The problem comes in when you want a nested URL structure but don’t want the page to be included in a navigation menu. What ends up happening is that even a page in the tree at Products > Widget Plus will only have a URL of /widgets-plus unless you check that “visible in navigation” check box.

In other words, you lose quite a bit of flexibility in URL structure if you want to build dynamic menus based on the value of that check box.

Give it a try (especially if you’re interested in Rails)

All-in-all, Alchemy CMS is the best open source Rails CMS that I’ve found. It is especially useful for those who are already proficient in Rails or want to learn. In other words, this is a great solution if a key part of your CMS decision is based on a desire to implement it in Ruby on Rails and not something like .NET or PHP.

I hope to share some more details of particular implementations and lessons learned in the coming months.

About Chris Peters

With over 20 years of experience, I help plan, execute, and optimize digital experiences.

Leave a comment