Dato::Rails

Use DatoCMS in your Rails application.

This gem allows you to fetch data using Dato GraphQL APIs and render the content in your Rails app.

👉 See this simple tutorial to get started on dev.to. 👈

Installation

Add this line to your application's Gemfile:

gem 'dato-rails', require: 'dato'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install dato-rails

The gem is made of two parts:

GraphQL client

The GraphQL client based on GQLi allows to perform queries to the GraphQL endpoint. Look at GQLi documentation for more information about the syntax of queries. You can also find some examples in specs of this library.

Set your api token as DATO_API_TOKEN environment variable.

client = Dato::Client.new # you can also pass the api token here.
query = GQLi::DSL.query {
  homepage {
    id
  }
}
response = client.execute(query)

puts response.data.homepage.id

We provide a fragment to extract a Responsive Image.

GQLi::DSL.query {
  homepage {
    id
    content {
      value
      blocks {
        __typename
        id
        image {
          responsiveImage(imgixParams: {fm: __enum("png")}) {
            ___ Dato::Fragments::ResponsiveImage
          }
        }
      }
    }
  }
}

View rendering

The library is also a Rails Engine and provides a whole set of ViewComponents to render your content. The library aims to provide the most basic components and make it easy to create new one.

Once you fetched the response of a query, you can use the Dato ViewComponents to render the content.

If you have a StructuredText component, you can render it with:

render Dato::StructuredText.new(response.data.homepage.content)

If you have a responsive image, you can render it with:

render Dato::ResponsiveImage.new(node.image.responsiveImage)

To define a custom node, you can create a new Dato::CustomNode view component in your application and it will be automatically used.

You can also customize how each node type is rendered by specifying the mapping on the single render:

render Dato::StructuredText.new(response.data.homepage.content, overrides: { link: Dato::NotRendered })

or globally:

# config/initializers/dato.rb

Dato::Config.overrides = {
  link: 'Dato::NotRendered'
}.with_indifferent_access

Preview and live

The Dato::Client supports both preview and live updates features from Dato CMS.

Dato::Client.new(preview: true) # to fetch draft versions

client = Dato::Client.new(live: true) # => to fetch a live straming URL 
client.live!(your_query)
# => { url: 'https://your_event_source_url' }

A ViewComponent is provided to use both these features very easily!

Given that you have a MyComponent that takes in input only the result of a dato query, you probably have the following:

result = Dato::Client.new.execute!(my_query)
render(MyComponent.new(result))

you can now wrap everything in a Dato::Live component like this:

render(Dato::Live.new(MyComponent, my_query, preview: true, live: true))

and your component will come to life with live updates 🎉 (requires turbo).

CRUD Operations

The library also provides a set of helpers to perform CRUD operations on Dato CMS.

All

Dato::Client.new.items.all(item_type_id: '456')

Find

Dato::Client.new.items.find(item_id: '123')

Create

Dato::Client.new.items.create(attributes: { title: 'Hello world' }, item_type_id: '456')

Update

Dato::Client.new.items.update(attributes: { title: 'Hello world' }, item_id: '123')

Destroy

Dato::Client.new.items.destroy(item_id: '123')

File upload

Dato Rails also supports file uploads. These can be created either from a local file or from a url. Basically all file types are supported, as long as they are valid in the CMS. Be aware that dato jobs are not synchronous, so you may need to implement some kind of polling to check if the upload is finished. The create method returns a job id, which can be used to retrieve the upload result.

In addition to the binary file, also attributes and metadata can be uploaded. Both metadata and attributes are optional. Provide attributes according to the docs

Upload from Url

Dato::Client.new.uploads.create_from_url('https://picsum.photos/seed/picsum/200/300')
Dato::Client.new.uploads.create_from_url('https://picsum.photos/seed/picsum/200/300', attributes:)

Upload from Local File

file = File.open('image.png')

Dato::Client.new.uploads.create_from_file(file.path)
Dato::Client.new.uploads.create_from_file(file.path, attributes:)

Optional: Attributes and metadata

meta = { en: { title: 'Static Random Image', alt: 'some caption text' } }
attributes = { author: 'Dato Rails', default_field_metadata: meta }

Optional: Filename

Dato::Client.new.uploads.create_from_url('https://picsum.photos/seed/picsum/200/300', filename: 'test.png')
Dato::Client.new.uploads.create_from_file(file.path, filename: 'test.png')

Getting the upload id

As the file upload is asynchronous, you may need to implement some kind of polling to check if the upload is finished. With the retrieve_job_result method you can retrieve the upload id from the job result.

job_id = client.uploads.create_from_file(file.path) # get back a job id
response = client.uploads.retrieve_job_result(job_id).parse # check the status
upload_id = response.dig('data', 'attributes', 'payload', 'data', 'id') # if nil, it's not done yet

Configuration

The following options are available:

# config/initializers/dato.rb

Dato::Config.configure do |config|
  config.overrides = {} # default: {}
  config.blocks = {} # default: {}
  config.cache = false # default: false
  config.cache_namespace = 'dato-rails' # default: 'dato-rails'
  config.publish_key = ENV['DATO_PUBLISH_KEY'] # default: ENV['DATO_PUBLISH_KEY']
  config.build_trigger_id = ENV['DATO_BUILD_TRIGGER_ID'] # default: ENV['DATO_BUILD_TRIGGER_ID']
end

Caching

The library supports caching of the rendered components. If you enable caching, the components rendered using Dato::Live, will be cached.

To enable caching, you need to set the cache option in the configuration.

# config/initializers/dato.rb

Dato::Config.configure do |config|
  config.cache = 1.day # if you set it to `true`, it will default to 60 minutes
end

Now a call to

render(Dato::Live.new(MyComponent, my_query))

will be cached for 1 day.

This means that for the next 24 hours, the graphQL endpoint will not be invoked and the whole component rendering will also be skipped.

We will cache the entire HTML result of the component, not only the graphQL response.

If you want to expire the cache you have two options:

manually

executing Rails.cache.clear(namespace: Dato::Config.cache_namespace)

publish endpoint

You can take advantage of the publish mechanism of Dato CMS to expire the cache.

  • Mount the dato-rails engine in your Rails routes file.
  • Set the DATO_PUBLISH_KEY environment variable
  • Create a build trigger with a custom webhook on your Dato CMS project setting.
  • Define the Trigger URL as https://yourapp.com/dato/publish
  • Set the DATO_PUBLISH_KEY as the Authorization header
  • Copy the build trigger id and set it as DATO_BUILD_TRIGGER_ID environment variable.

Development

After checking out the repo, run bundle install to install dependencies.

You can now clone the dato-rails project

Clone DatoCMS project

You then need to set a DATO_API_TOKEN=abcd123x in the .env file on the root of your project to consume data from your project. For testing purposes, set TEST_MODEL_TYPE_ID=1234 in the .env file with the id of the author model type in your project.

Then, run bundle exec rspec to run the tests.

You can also run rails 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 the created tag, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/renuo/dato-rails. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the Dato::Rails project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.