---
url: /reference/concerns/contentable.md
---
# Trek::Contentable

Utilities for content stored as ProseMirror JSON in a `content` column — the format produced by Trek's [content editor](/content-editor).

## Methods

| Method | Returns |
| --- | --- |
| `parsed_content` | the content as a hash (parsing JSON strings if needed) |
| `content_document` | the content as a `Prosemirror::Document`, to query or render it |
| `formatted_content` | safe HTML, rendered as described in [Rendering on the site](/content-editor#rendering-on-the-site) |
| `content_text` | the plain text of the content: blocks separated by a blank line, hard breaks by a newline |
| `prosemirror_content?` | whether `content` is a valid ProseMirror document |

## Usage

```ruby
class Page < ApplicationRecord
  include Trek::Contentable
end

page.formatted_content # => "<p>Hello <strong>world</strong></p>"
page.content_text      # => "Hello world"
```

Content in another column renders through the same schema: `Trek::Content::Document.parse(record, record.intro).to_html`. See the [Content editor](/content-editor) guide for the whole path, from the editor to the HTML.

## Cleaning before saving

Before validation, empty paragraphs, empty list items and lists left empty are removed from the content, as rendering skips them (`Trek::Content::Cleaner`). The document stays one the editor opens: an empty document keeps one paragraph, a list item keeps the first paragraph it needs, and node types or attributes the schema doesn't know are kept. Content submitted as a JSON string, as the content editor sends it, is stored as a document. Translated content is cleaned in the current locale.

## Requirements

* A `content` jsonb column
* Used by [Page](/reference/models/page) and [Fragment](/reference/models/fragment)
