# Renderful [![CircleCI](https://circleci.com/gh/bestmadeco/renderful.svg?style=svg)](https://circleci.com/gh/bestmadeco/renderful) Welcome! Renderful is a rendering engine for [Contentful](https://www.contentful.com) spaces. It allows you to map your content types to Ruby objects that take care of rendering your content. ## Installation Add this line to your application's Gemfile: ```ruby gem 'renderful' ``` And then execute: ```console $ bundle ``` Or install it yourself as: ```console $ gem install renderful ``` Once you have installed the gem, you can configure it like this: ```ruby contentful = Contentful::Client.new( space: 'CONTENTFUL_SPACE_ID', access_token: 'CONTENTFUL_ACCESS_TOKEN', ) renderful = Renderful.new( contentful: contentful, renderers: { 'jumbotron' => JumbotronRenderer, } ) ``` ## Usage Suppose you have the `jumbotron` content type in your Contentful space. This content type has the `title` and `content` fields, both strings. Let's create the `app/renderers/jumbotron_renderer.rb` file: ```ruby class JumbotronRenderer < Renderful::Renderer def render <<~HTML

<%= entry.title %>

<%= entry.content %>

HTML end end ``` You can now render this component by retrieving it from Contentful and rendering it with Renderful: ```ruby entry = contentful.entry('jumbotron_entry_id') renderful.render(entry) ``` ### Rich text rendering If you have rich-text fields, you can leverage Contentful's [rich_text_renderer](https://github.com/contentful/rich-text-renderer.rb) along with a custom local variable: ```ruby class TextBlockRenderer < Renderful::Renderer::Rails def html_body RichTextRenderer::Renderer.new.render(entry.body) end def locals { html_body: html_body } end end ``` Then, just reference the `html_body` variable as usual: ```erb <%# app/views/renderful/_text_block.html.erb %> <%= raw html_body %> ``` ### Nested components What if you want to have a `Grid` component that can contain references to other components? It's actually quite simple! Simply create a _References_ field for your content, then recursively render all of the content entries contained in that field: ```ruby # app/components/grid.rb class Grid < Renderful::Renderer # This will define a `resolved_blocks` method that reads external references # from the `blocks` fields and turns them into Contentful::Entry instances resolve :blocks def render entries = blocks.map do |block| # `client` can be used to access the Renderful::Client instance <<~HTML
#{client.render(block)}
HTML end <<~HTML
#{entries}
HTML end end ``` ### Caching You can easily cache the output of your renderers by passing a `cache` key when instantiating the client. The value of this key should be an object that responds to the following methods: - `#read(key)` - `#write(key, value)` - `#delete(key)` - `#exist?(key)` A Redis cache implementation is included out of the box. Here's an example: ```ruby renderful = Renderful.new( contentful: contentful, cache: Renderful::Cache::Redis.new(Redis.new(url: 'redis://localhost:6379')), renderers: { 'jumbotron' => JumbotronRenderer } ) ``` If you are using Rails and want to use the Rails cache store for Renderful, you can simply pass `Rails.cache`, which responds to the expected interface: ```ruby renderful = Renderful.new( contentful: contentful, cache: Rails.cache, renderers: { 'jumbotron' => JumbotronRenderer } ) ``` #### Cache invalidation The best way to invalidate the cache is through [Contentful webhooks](https://www.contentful.com/developers/docs/concepts/webhooks/). Renderful ships with a framework-agnostic webhook processor you can use to automatically invalidate the cache for all updated content: ```ruby Renderful::CacheInvalidator.new(renderful).process_webhook(json_body) ``` This is how you could use it in a Rails controller: ```ruby class ContentfulWebhooksController < ApplicationController def create Renderful::CacheInvalidator.new(RenderfulClient).process_webhook(request.raw_post) head :no_content end end ``` ### Rails integration If you are using Ruby on Rails and you want to use ERB instead of including HTML in your renderers, you can inherit from the Rails renderer: ```ruby class JumbotronRenderer < Renderful::Renderer::Rails end ``` Then, create an `app/views/renderful/_jumbotron.html.erb` partial: ```erb

<%= entry.title %>

<%= entry.content %>

``` As you can see, you can access the Contentful entry via the `entry` local variable. #### Custom renderer The Rails renderer uses `ActionController::Base.renderer` by default, but this prevents you from using your own helpers in components. If you want to use a different renderer instead, you can override the `renderer` method: ```ruby class JumbotronRenderer < Renderful::Renderer::Rails def renderer ApplicationController.renderer end end ``` #### Custom locals If you want, you can also add your own locals: ```ruby class JumbotronRenderer < Renderful::Renderer::Rails def locals italian_title = entry.title.gsub(/hello/, 'ciao') { italian_title: italian_title } end end ``` You would then access them like regular locals: ```erb

<%= entry.title %> (<%= italian_title %>)

<%= entry.content %>

``` #### Resolution in ERB views If you need to render resolved fields (as in our `Grid` example), you can use `renderer` and `client` to access the `Renderful::Renderer` and `Renderful::Client` objects: ```erb <%# app/views/renderful/_grid.html.erb %>
<% renderer.blocks.each do |block| %>
<%= client.render(block) %>
<% end %>
``` ## Development After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). ## Contributing Bug reports and pull requests are welcome on GitHub at https://github.com/bestmadeco/renderful. ## License The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). ## Credits Renderful is sponsored and maintained by [Bolt Threads Inc.](https://www.boltthreads.com).