The project is in a healthy, maintained state
Build complex contents for your ActiveRecord models in a controllable way.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

~> 2.1
~> 13.0
~> 3.10

Runtime

 Project Readme

CompositeContent

Unit tests Gem Version

CompositeContent add capacities to your Rails application to manage complex contents made of blocks with ease.

Some Background

Rich administrable contents used to be managed through WYSIWYG editors. This leaves you with a very poor control over what is allowed inside such content areas and how it will be rendered afterwards: img tags may include the full picture as base64 data or, like iframes (pasted from videos or slides sharing code), can have hard-coded dimensions that makes them hard to manipulate in a responsive design; titles hierarchy may not semantically fit in every context where your content will be displayed; rogue CSS classes can be pasted from word processors without being noticed.
The list of potential problems in a responsive and multi-channel world goes on…

The Rails team did an amazing work to go one step forward with ActionText and its integration of ActiveStorage. But the Trix editor supports very few options on content types supported by default, seems to have some limitation on extending them to offer more, requires to create custom elements to support new content types (ex: application models) and does not output semantic HTML markup.
Great, but there should be a better way…

An alternative to a monolithic WYSIWYG editor is to split your content into manageable chunks, or blocks. Each type of block can have its own properties and options and their definition should give you the ability to carefully manage their content to integrate it in various use cases and/or with other parts of your application. Such system should be extensible, so you can create new types of blocks to fit your needs.

For example:

  • An image block can use your favorite attachment solution to retain picture information and be able to render it with the appropriate src-set attribute to accommodate screen resolutions you support.
  • A video block can be rendered in a custom made player.
  • A button block can survive your next redesign.
  • Knowing your titles hierarchy inside a long content can gives you the ability to automate building of a table of content.
  • A dedicated block type can help you to integrate descriptions of one or more of your products into a blog post.

CompositeContent provides basis for a composite content management on your models, in a way that can be compared to article construction on medium.com or to the WordPress Gutenberg editor, and aims to integrate well with your Rails application. It's voluntarily kept simple so you can plug your favorite tools in and style it to integrate well with your design.

Installation

CompositeContent is distributed as a gem and available on rubygems.org so you can add it to your Gemfile or install it manually with:

gem install composite_content

Once the gem is installed, you need to integrate it with your Rails application.

# Copy CompositeContent's engine files into your app:
# - Views to app/views/composite_content
# - Database migrations to db/migrate
$ rails g composite_content:install

# Apply migrations
$ rails db:migrate 

Important: For forms to work, you also need to integrate assets from the Cocooned gem with yours. As there is multiple ways to do so, wether you use Sprockets, webpacker/shakapacker or importmaps, we won't describe this step in details here.

Usage

In your models, you can declare one or more CompositeContent per model.

class Article < ApplicationRecord
  # You can use the default content slot name (:composite_content)…
  has_composite_content
end

class Page < ApplicationRecord
  # …or give it a name that is explicit for you.
  has_composite_content :main
  
  # You can specify what kinds of blocks you accept in a content slot.
  has_composite_content :aside, types: %w(CompositeContent::Blocks::Text)
end

Strong Parameters

In your controllers, allow composite content attributes with:

class ArticleController < ApplicationController
  # […]
  def article_params
    params.require(:article)
          .permit(:title,
                  composite_content_attributes: Article.strong_parameters_for_composite_content)
  end
end

class PageController < ApplicationController
  # […]
  def page_params
    params.require(:page)
          .permit(:title,
                  main_attributes: Page.strong_parameters_for_main,
                  aside_attributes: Page.strong_parameters_for_aside)
  end
end

Views

In your forms, make composite content editable with:

<%= form.fields_for :composite_content do |composite_content_form| %>
  <%= render "#{CompositeContent::Engine.config.views_path}/slot/form", form: composite_content_form %>
<% end %>

In your views, render the content of a slot with:

<%= composite_content_render_slot(article.composite_content) %>

<%= composite_content_render_slot(page.main) %>
<%= composite_content_render_slot(page.aside) %>

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/notus-sh/composite_content.