dato-rails 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +9 -23
- data/app/components/dato/block.html.erb +18 -11
- data/app/components/dato/dast_node.rb +6 -0
- data/app/components/dato/inline_block.html.erb +20 -0
- data/app/components/dato/inline_block.rb +7 -0
- data/app/components/dato/inline_item.html.erb +39 -0
- data/app/components/dato/inline_item.rb +4 -0
- data/app/components/dato/item_link.html.erb +18 -0
- data/app/components/dato/item_link.rb +20 -0
- data/app/components/dato/link.rb +0 -6
- data/app/components/dato/node.rb +28 -0
- data/app/components/dato/paragraph.rb +1 -1
- data/app/components/dato/structured_text.rb +2 -0
- data/app/components/dato/unknown_block.html.erb +18 -17
- data/app/components/dato/unknown_node.html.erb +14 -14
- data/lib/dato/config.rb +2 -0
- data/lib/dato/engine.rb +2 -0
- data/lib/dato/gql.rb +4 -3
- data/lib/dato/railties/controller_runtime.rb +8 -3
- data/lib/dato/version.rb +1 -1
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1973ec82f04620deeaf8b94c8b8fe4816c60f5c00cf0ccfba93ab38e938af5fb
|
4
|
+
data.tar.gz: 1f83767d11f764f199b4bf394da6d216a237d22a37fee001542413f5f183ab61
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 69b37b143b7e6f422c28f3b74677991d876a5bd181e3ebf97e9bc93d31165404bc39c32991cdbf3cd635c640fde730cc564a00c002ff4cf725870ec2703282c4
|
7
|
+
data.tar.gz: b9f95b4994a61b6801a781ba3369e679a1dbfc012d356a213de48b30bbab8a54ca2282d33a7754368c3b12b594b8b22ec265dc89b4776c083c0086707cf97dea
|
data/README.md
CHANGED
@@ -5,7 +5,8 @@ Use [DatoCMS](https://www.datocms.com/) in your Rails application.
|
|
5
5
|
This gem allows you to fetch data using Dato GraphQL APIs and render the content in your Rails app.
|
6
6
|
|
7
7
|
👉 See [this simple tutorial to get started on dev.to](https://dev.to/coorasse/datocms-with-ruby-on-rails-3ae5). 👈
|
8
|
-
|
8
|
+
|
9
|
+
👉 See also [this second tutorial to build a Blog](https://dev.to/coorasse/rails-blog-with-datocms-2h1e). 👈
|
9
10
|
|
10
11
|
## Installation
|
11
12
|
|
@@ -89,24 +90,7 @@ If you have a responsive image, you can render it with:
|
|
89
90
|
render Dato::ResponsiveImage.new(node.image.responsiveImage)
|
90
91
|
```
|
91
92
|
|
92
|
-
|
93
|
-
automatically used.
|
94
|
-
|
95
|
-
You can also customize how each node type is rendered by specifying the mapping on the single render:
|
96
|
-
|
97
|
-
```ruby
|
98
|
-
render Dato::StructuredText.new(response.data.homepage.content, overrides: { link: Dato::NotRendered })
|
99
|
-
```
|
100
|
-
|
101
|
-
or globally:
|
102
|
-
|
103
|
-
```
|
104
|
-
# config/initializers/dato.rb
|
105
|
-
|
106
|
-
Dato::Config.overrides = {
|
107
|
-
link: 'Dato::NotRendered'
|
108
|
-
}.with_indifferent_access
|
109
|
-
```
|
93
|
+
Read more about [StructuredText - Custom Nodes](docs/custom_nodes.md).
|
110
94
|
|
111
95
|
## Preview and live
|
112
96
|
|
@@ -243,6 +227,7 @@ Dato::Config.configure do |config|
|
|
243
227
|
config.api_token = ENV['DATO_PUBLISH_KEY'] # default: ENV.fetch("DATO_API_TOKEN", Rails.application.credentials.dig(:dato, :api_token))
|
244
228
|
config.publish_key = ENV['DATO_PUBLISH_KEY'] # default: ENV.fetch("DATO_PUBLISH_KEY", Rails.application.credentials.dig(:dato, :publish_key))
|
245
229
|
config.build_trigger_id = ENV['DATO_BUILD_TRIGGER_ID'] # default: ENV.fetch("DATO_BUILD_TRIGGER_ID", Rails.application.credentials.dig(:dato, :build_trigger_id))
|
230
|
+
config.base_editing_url = ENV['DATO_BASE_EDITING_URL'] # default: ENV.fetch("DATO_BASE_EDITING_URL", Rails.application.credentials.dig(:dato, :base_editing_url))
|
246
231
|
config.mount_path = '/dato' # default: '/dato'
|
247
232
|
end
|
248
233
|
```
|
@@ -285,18 +270,20 @@ executing `Dato::Cache.clear!` or running `bin/rails dato:cache:clear`.
|
|
285
270
|
|
286
271
|
You can take advantage of the publish mechanism of Dato CMS to expire the cache.
|
287
272
|
|
288
|
-
*
|
273
|
+
* Generate a new secret key with `bin/rails secret` and set it as `DATO_PUBLISH_KEY` environment variable or in Rails Credentials as `dato.publish_key`.
|
289
274
|
* Create a build trigger with a custom webhook on your Dato CMS project setting.
|
290
275
|
* Define the Trigger URL as `https://yourapp.com/dato/publish`
|
291
276
|
* Set the `DATO_PUBLISH_KEY` as the Authorization header
|
292
277
|
* Copy the build trigger id and set it as `DATO_BUILD_TRIGGER_ID` environment variable.
|
293
278
|
|
279
|
+

|
280
|
+
|
294
281
|
### Caching of graphQL response / Controller helpers
|
295
282
|
|
296
283
|
If you are not using ViewComponents or you need to cache a single GraphQL query, you can still do it using the
|
297
284
|
`Dato::Cache` helper.
|
298
285
|
|
299
|
-
In your controllers you already have a helper method `execute_dato_query
|
286
|
+
In your controllers you already have a helper method `execute_dato_query!`.
|
300
287
|
You can use it in your controller action and queries results will be automatically cached if:
|
301
288
|
|
302
289
|
* You have `Dato` cache enabled
|
@@ -304,7 +291,7 @@ You can use it in your controller action and queries results will be automatical
|
|
304
291
|
* you are not displaying a preview
|
305
292
|
|
306
293
|
```ruby
|
307
|
-
response = execute_dato_query(blog_post_query(params[:slug]), preview: params[:preview])
|
294
|
+
response = execute_dato_query!(blog_post_query(params[:slug]), preview: params[:preview])
|
308
295
|
@data = response.data
|
309
296
|
```
|
310
297
|
|
@@ -321,7 +308,6 @@ Completed 200 OK in 365ms (Views: 109.5ms | ActiveRecord: 0.7ms (4 queries, 0 ca
|
|
321
308
|
|
322
309
|
this is useful to identify if the bottleneck is in the fetching of the data from Dato CMS.
|
323
310
|
|
324
|
-
|
325
311
|
## Development
|
326
312
|
|
327
313
|
After checking out the repo, run `bundle install` to install dependencies.
|
@@ -1,13 +1,20 @@
|
|
1
|
-
<% block = blocks
|
2
|
-
<% if block.
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
1
|
+
<% block = blocks&.find { |b| b.id == @node.item } %>
|
2
|
+
<% if block.nil? %>
|
3
|
+
<%= error_block do %>
|
4
|
+
There is a block with id <code><%= @node.item %></code> that has not been retrieved by the GraphQL Query.<br>
|
5
|
+
It's possible that your query is returning a structured text without blocks.
|
6
|
+
<% end %>
|
7
|
+
<% elsif block.__typename.nil? %>
|
8
|
+
<%= error_block do %>
|
9
|
+
In order to render a block, you need to return its <code>__typename</code>.<br>
|
10
|
+
In your GraphQL query, add <code>__typename</code> to the list of fields returned for the blocks.<br>
|
11
|
+
For example:<br><br>
|
12
|
+
<code>
|
13
|
+
blocks {
|
14
|
+
__typename
|
15
|
+
}
|
16
|
+
</code>
|
17
|
+
<% end %>
|
11
18
|
<% else %>
|
12
|
-
<%=render class_for_block(block).new(block, root) %>
|
19
|
+
<%= render class_for_block(block).new(block, root) %>
|
13
20
|
<% end %>
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<% block = blocks&.find { |b| b.id == @node.item } %>
|
2
|
+
<% if block.nil? %>
|
3
|
+
<%= error_block do %>
|
4
|
+
There is an inline block with id <code><%= @node.item %></code> that has not been retrieved by the GraphQL Query.<br>
|
5
|
+
It's possible that your query is returning a structured text without blocks.
|
6
|
+
<% end %>
|
7
|
+
<% elsif block.__typename.nil? %>
|
8
|
+
<%= error_block do %>
|
9
|
+
In order to render an inline block, you need to return its <code>__typename</code>.<br>
|
10
|
+
In your GraphQL query, add <code>__typename</code> to the list of fields returned for the blocks.<br>
|
11
|
+
For example:<br><br>
|
12
|
+
<code>
|
13
|
+
blocks {
|
14
|
+
__typename
|
15
|
+
}
|
16
|
+
</code>
|
17
|
+
<% end %>
|
18
|
+
<% else %>
|
19
|
+
<%= render class_for_block(block).new(block, root) %>
|
20
|
+
<% end %>
|
@@ -0,0 +1,39 @@
|
|
1
|
+
<% inline_item = links.find { |b| b.id == @node.item } %>
|
2
|
+
|
3
|
+
<% if inline_item.present? %>
|
4
|
+
<% if class_for_inline_item(inline_item).present? %>
|
5
|
+
<%= render class_for_inline_item(inline_item).new(inline_item, root) %>
|
6
|
+
<% elsif path_for_inline_item(inline_item).present? %>
|
7
|
+
<%= link_to inline_item.title, path_for_inline_item(inline_item), class: "dato-cms-#{@node.type}" %>
|
8
|
+
<% else %>
|
9
|
+
<%= error_block do %>
|
10
|
+
This is an unknown InlineItem. Here is the content:<br>
|
11
|
+
<pre><%= JSON.pretty_generate(inline_item) %></pre>
|
12
|
+
This is a link, so you have some options:
|
13
|
+
<ul>
|
14
|
+
<li>Define the function to generate path for this item. For example:<br>
|
15
|
+
<code>
|
16
|
+
config.links_mapping = {<br>
|
17
|
+
'<%= inline_item.__typename %>' => ->(inline_item) { blog_post_path(inline_item.slug) }<br>
|
18
|
+
}<br>
|
19
|
+
</code>
|
20
|
+
This will use the default link renderer, and set the href attribute according to your definition.
|
21
|
+
</li>
|
22
|
+
<li>
|
23
|
+
Define a class in your <code>app/components/dato</code> folder. For example:<br>
|
24
|
+
<code>
|
25
|
+
class <%= class_by_type(inline_item.__typename) %> < Dato::Node<br>
|
26
|
+
...<br>
|
27
|
+
end<br>
|
28
|
+
</code><br>
|
29
|
+
</li>
|
30
|
+
<li>Not render it by excluding it from your GraphQL Query</li>
|
31
|
+
<li>Not render it by using the overrides: <code>{overrides: '<%= @node.__typename %>': Dato::NotRendered }</code></li>
|
32
|
+
</ul>
|
33
|
+
<% end %>
|
34
|
+
<% end %>
|
35
|
+
<% else %>
|
36
|
+
<%= error_block do %>
|
37
|
+
I don't know this inline item.
|
38
|
+
<% end %>
|
39
|
+
<% end %>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<% if inline_item.__typename.nil? %>
|
2
|
+
<%= error_block do %>
|
3
|
+
In order to render an item link, you need to return its <code>__typename</code>.<br>
|
4
|
+
In your GraphQL query, add <code>__typename</code> to the list of fields returned for the blocks.<br>
|
5
|
+
For example:<br><br>
|
6
|
+
<code>
|
7
|
+
links {
|
8
|
+
__typename
|
9
|
+
}
|
10
|
+
</code>
|
11
|
+
<% end %>
|
12
|
+
<% else %>
|
13
|
+
<%= tag.a(**link_attributes) do -%>
|
14
|
+
<% @node.children&.each do |node| -%>
|
15
|
+
<%= render_node(node) -%>
|
16
|
+
<% end -%>
|
17
|
+
<% end -%>
|
18
|
+
<% end %>
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Dato::ItemLink < Dato::DastNode
|
4
|
+
def initialize(node, root)
|
5
|
+
super(node, "itemLink", root)
|
6
|
+
end
|
7
|
+
|
8
|
+
def inline_item
|
9
|
+
links.find { |b| b.id == @node.item }
|
10
|
+
end
|
11
|
+
|
12
|
+
def link_attributes
|
13
|
+
attr = {
|
14
|
+
"href" => path_for_inline_item(inline_item),
|
15
|
+
"class" => "dato-cms-#{@node.type}"
|
16
|
+
}
|
17
|
+
%w[rel target].each { |type| attr[type] = extract_meta(type) }
|
18
|
+
attr
|
19
|
+
end
|
20
|
+
end
|
data/app/components/dato/link.rb
CHANGED
data/app/components/dato/node.rb
CHANGED
@@ -17,6 +17,10 @@ module Dato
|
|
17
17
|
root.blocks
|
18
18
|
end
|
19
19
|
|
20
|
+
def links
|
21
|
+
root.links
|
22
|
+
end
|
23
|
+
|
20
24
|
def overrides
|
21
25
|
root.overrides
|
22
26
|
end
|
@@ -39,6 +43,25 @@ module Dato
|
|
39
43
|
end
|
40
44
|
end
|
41
45
|
|
46
|
+
def class_for_inline_item(inline_item)
|
47
|
+
class_name = overrides[inline_item.__typename] || Dato::Config.overrides[inline_item.__typename]
|
48
|
+
if class_name.is_a?(String)
|
49
|
+
class_name = class_name.constantize
|
50
|
+
end
|
51
|
+
begin
|
52
|
+
class_name || class_by_type(inline_item.__typename).constantize
|
53
|
+
rescue NameError
|
54
|
+
nil
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def path_for_inline_item(inline_item)
|
59
|
+
lambda = Dato::Config.links_mapping[inline_item.__typename]
|
60
|
+
if lambda
|
61
|
+
instance_exec(inline_item, &lambda)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
42
65
|
def class_for_node(node)
|
43
66
|
class_name = overrides[node.type] || Dato::Config.overrides[node.type]
|
44
67
|
if class_name.is_a?(String)
|
@@ -54,5 +77,10 @@ module Dato
|
|
54
77
|
def class_by_type(type)
|
55
78
|
"Dato::#{type.classify}"
|
56
79
|
end
|
80
|
+
|
81
|
+
def error_block(&block)
|
82
|
+
content = capture(&block)
|
83
|
+
content_tag(:div, content, style: "border: 3px dotted limegreen; display: inline-block; padding: 5px;font-weight: bold")
|
84
|
+
end
|
57
85
|
end
|
58
86
|
end
|
@@ -13,6 +13,7 @@ class Dato::StructuredText < Dato::Node
|
|
13
13
|
@overrides = overrides.with_indifferent_access
|
14
14
|
@structured_text_node = structured_text_node
|
15
15
|
@blocks = structured_text_node.blocks
|
16
|
+
@links = structured_text_node.links
|
16
17
|
end
|
17
18
|
|
18
19
|
def root
|
@@ -20,6 +21,7 @@ class Dato::StructuredText < Dato::Node
|
|
20
21
|
end
|
21
22
|
|
22
23
|
attr_reader :blocks
|
24
|
+
attr_reader :links
|
23
25
|
|
24
26
|
attr_reader :overrides
|
25
27
|
end
|
@@ -1,17 +1,18 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
<
|
16
|
-
|
17
|
-
</
|
1
|
+
<%= error_block do %>
|
2
|
+
This is an unknown block. Here is the content:<br>
|
3
|
+
<pre><%= JSON.pretty_generate(@node) %></pre>
|
4
|
+
In order to render it, you need to define a ViewComponent named <code><%= class_by_type(@node.__typename) %></code>.
|
5
|
+
<br>
|
6
|
+
You can define this class in your <code>app/components/dato</code> folder. For example:<br><br>
|
7
|
+
<code>
|
8
|
+
class <%= class_by_type(@node.__typename) %> < Dato::Node<br>
|
9
|
+
...<br>
|
10
|
+
end<br>
|
11
|
+
</code><br>
|
12
|
+
If you don't want to render this block you can:
|
13
|
+
<ul>
|
14
|
+
<li>not return it in your GraphQL query</li>
|
15
|
+
<li>override the component when rendering the root <code>Dato::StructuredText</code> node.<br>
|
16
|
+
<code>Dato::StructuredText.new(content, overrides: { '<%= @node.__typename %>': Dato::NotRendered })</code></li>
|
17
|
+
</ul>
|
18
|
+
<% end %>
|
@@ -1,15 +1,15 @@
|
|
1
|
-
|
2
|
-
<
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
</
|
1
|
+
<%= error_block do %>
|
2
|
+
This is an unknown node of type <code><%= @type %></code>. Here is the content:<br>
|
3
|
+
<pre><%= JSON.pretty_generate(@node) %></pre>
|
4
|
+
In order to render it, you need to define a ViewComponent named <code><%= class_by_type(@node.type) %></code>.<br>
|
5
|
+
You can define this class in your <code>app/components/dato</code> folder. For example:<br><br>
|
6
|
+
<code>
|
7
|
+
class <%= class_by_type(@node.type) %> < Dato::Node<br>
|
8
|
+
...<br>
|
9
|
+
end<br>
|
10
|
+
</code><br>
|
11
|
+
If you don't want to render this node, you can override the component when rendering the root
|
12
|
+
<code>Dato::StructuredText</code> node.<br>
|
13
|
+
<code>Dato::StructuredText.new(content, overrides: { link: Dato::NotRendered })</code>
|
14
14
|
<%= debug_node %>
|
15
|
-
|
15
|
+
<% end %>
|
data/lib/dato/config.rb
CHANGED
@@ -3,12 +3,14 @@ module Dato
|
|
3
3
|
include ActiveSupport::Configurable
|
4
4
|
|
5
5
|
config_accessor(:overrides) { {} }
|
6
|
+
config_accessor(:links_mapping) { {} }
|
6
7
|
config_accessor(:blocks) { {} }
|
7
8
|
config_accessor(:cache) { false }
|
8
9
|
config_accessor(:cache_namespace) { "dato-rails" }
|
9
10
|
config_accessor(:api_token) { ENV.fetch("DATO_API_TOKEN", Rails.application.credentials.dig(:dato, :api_token)) }
|
10
11
|
config_accessor(:publish_key) { ENV.fetch("DATO_PUBLISH_KEY", Rails.application.credentials.dig(:dato, :publish_key)) }
|
11
12
|
config_accessor(:build_trigger_id) { ENV.fetch("DATO_BUILD_TRIGGER_ID", Rails.application.credentials.dig(:dato, :build_trigger_id)) }
|
13
|
+
config_accessor(:base_editing_url) { ENV.fetch("DATO_BASE_EDITING_URL", Rails.application.credentials.dig(:dato, :base_editing_url)) }
|
12
14
|
config_accessor(:mount_path) { "/dato" }
|
13
15
|
end
|
14
16
|
end
|
data/lib/dato/engine.rb
CHANGED
data/lib/dato/gql.rb
CHANGED
@@ -2,11 +2,12 @@ module Dato
|
|
2
2
|
class Gql < GQLi::Client
|
3
3
|
def initialize(api_token, validate_query, preview, live)
|
4
4
|
@api_token = api_token
|
5
|
+
headers = {"Authorization" => @api_token}
|
6
|
+
headers["X-Base-Editing-Url"] = Dato::Config.base_editing_url if Dato::Config.base_editing_url.present?
|
7
|
+
|
5
8
|
super(
|
6
9
|
"https://graphql#{"-listen" if live}.datocms.com/#{"preview" if preview}",
|
7
|
-
headers:
|
8
|
-
"Authorization" => @api_token
|
9
|
-
},
|
10
|
+
headers: headers,
|
10
11
|
validate_query: validate_query && !live
|
11
12
|
)
|
12
13
|
end
|
@@ -5,9 +5,7 @@ module Dato
|
|
5
5
|
|
6
6
|
def execute_dato_query(query, preview: false)
|
7
7
|
client = Dato::Client.new(preview: preview)
|
8
|
-
if preview
|
9
|
-
return client.execute!(query)
|
10
|
-
end
|
8
|
+
return client.execute!(query) if preview
|
11
9
|
|
12
10
|
key = "#{Digest::MD5.hexdigest(query.to_gql)}-query-#{preview}"
|
13
11
|
Dato::Cache.fetch(key) do
|
@@ -15,6 +13,13 @@ module Dato
|
|
15
13
|
end
|
16
14
|
end
|
17
15
|
|
16
|
+
def execute_dato_query!(query, preview: false)
|
17
|
+
response = execute_dato_query(query, preview: preview)
|
18
|
+
raise(InvalidGraphqlQuery, response.errors.first.message) if response.errors&.any?
|
19
|
+
|
20
|
+
response
|
21
|
+
end
|
22
|
+
|
18
23
|
module ClassMethods # :nodoc:
|
19
24
|
def log_process_action(payload)
|
20
25
|
messages = super
|
data/lib/dato/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dato-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alessandro Rodi
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-02-27 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: rspec-rails
|
@@ -186,6 +186,12 @@ files:
|
|
186
186
|
- app/components/dato/heading.rb
|
187
187
|
- app/components/dato/image_block_record.html.erb
|
188
188
|
- app/components/dato/image_block_record.rb
|
189
|
+
- app/components/dato/inline_block.html.erb
|
190
|
+
- app/components/dato/inline_block.rb
|
191
|
+
- app/components/dato/inline_item.html.erb
|
192
|
+
- app/components/dato/inline_item.rb
|
193
|
+
- app/components/dato/item_link.html.erb
|
194
|
+
- app/components/dato/item_link.rb
|
189
195
|
- app/components/dato/link.html.erb
|
190
196
|
- app/components/dato/link.rb
|
191
197
|
- app/components/dato/list.rb
|