wcc-contentful 1.0.0.pre.rc2 → 1.0.0.pre.rc3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +92 -6
  3. data/lib/wcc/contentful/version.rb +1 -1
  4. metadata +110 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 641600f1bd3c583aad140a1505a02d3121cf6b0e4cac4a2484fc49d3c1134003
4
- data.tar.gz: 233f01f125d9f30a4bc6ecd820f350a315c4a87d6813b5edf85750fe2179a97c
3
+ metadata.gz: b5cae24e96be56167418f05f625fdede6e0f4bfe0c9a87265b4098bf6906a6ca
4
+ data.tar.gz: ddad1d967c0e181cd3ecd97ab571f0e05a5228e158deefb6edf81c653750e99e
5
5
  SHA512:
6
- metadata.gz: 699e37d8ca2948f4ddc8feb90a9850cbbc602e17fa3e7e62d99fe84944198d3b7ed8c253e823fa830717c5c491fa7e2d796bdc97923346a20012d8742b011414
7
- data.tar.gz: cc5919e973428a78193e7821e9402a997deede747419f86810ba692a75f8493a35397e9c5c6a30d88d16302fd7d50d3228216b80d593b24564036ed0ffd4ffff
6
+ metadata.gz: 7ff892d606377aafec3529eb45c1bac84ba7e2b3c877eacbccd09ec6ea5331d60db6afacaf7152e0716ea9da7ec8864e61a937f954873992428353bd7179e916
7
+ data.tar.gz: 6c22be5cc52e788dfa5e5536b76b855508b27230c7c6120ecb10e23b6a7e4b190470ffc7ec2a5b81f0fac57874047130a85e15ab561cc90a691afb4e1116dcd7
data/README.md CHANGED
@@ -2,10 +2,92 @@
2
2
  [![Build Status](https://travis-ci.org/watermarkchurch/wcc-contentful.svg?branch=master)](https://travis-ci.org/watermarkchurch/wcc-contentful)
3
3
  [![Coverage Status](https://coveralls.io/repos/github/watermarkchurch/wcc-contentful/badge.svg?branch=master)](https://coveralls.io/github/watermarkchurch/wcc-contentful?branch=master)
4
4
 
5
- Full documentation: https://www.rubydoc.info/gems/wcc-contentful
5
+ Full documentation: https://watermarkchurch.github.io/wcc-contentful/latest/wcc-contentful/
6
6
 
7
7
  # WCC::Contentful
8
8
 
9
+ An alternative to Contentful's [contentful.rb ruby client](https://github.com/contentful/contentful.rb/), [contentful_model](https://github.com/contentful/contentful_model), and [contentful_rails](https://github.com/contentful/contentful_rails) gems all in one.
10
+
11
+ Table of Contents:
12
+
13
+ 1. [Why?](#why-did-you-rewrite-the-contentful-ruby-stack)
14
+ 2. [Installation](#installation)
15
+
16
+ ## Why did you rewrite the Contentful ruby stack?
17
+
18
+ We started working with Contentful almost 3 years ago. Since that time, Contentful's ruby stack has improved, but there are still a number of pain points that we feel we have addressed better with our gem. These are:
19
+
20
+ * [Low-level caching](#low-level-caching)
21
+ * [Better integration with Rails & Rails models](#better-rails-integration)
22
+ * [Automatic pagination and Automatic link resolution](#automatic-pagination-and-link-resolution)
23
+ * [Automatic webhook management](#automatic-webhook-management)
24
+
25
+ Our gem no longer depends on any of the Contentful gems and interacts directly with the [Contentful CDA](https://www.contentful.com/developers/docs/references/content-delivery-api/) and [Content Management API](https://www.contentful.com/developers/docs/references/content-management-api/) over HTTPS.
26
+
27
+ ### Low-level caching
28
+
29
+ The wcc-contentful gem enables caching at two levels: the HTTP response using [Faraday HTTP cache middleware](https://github.com/sourcelevel/faraday-http-cache), and at the Entry level using the Rails cache and the [Sync API](https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/synchronization) to keep it up to date. We've found these two cache layers to be very effective at reducing both round trip latency to the Content Delivery API, as well as reducing our monthly API request usage. (which reduces our overage charges. Hooray!)
30
+
31
+ #### At the request/response level
32
+ By default, the contentful.rb gem requires the [HTTP library](https://rubygems.org/gems/http). While simple and straightforward to use, it is not as powerful for caching. We decided to make our client conform to the [Faraday gem's API](https://github.com/lostisland/faraday). If you prefer not to use Faraday, you can choose to supply your own HTTP adapter that "quacks like" Faraday (see the [TyphoeusAdapter](https://github.com/watermarkchurch/wcc-contentful/blob/master/wcc-contentful/lib/wcc/contentful/simple_client/typhoeus_adapter.rb) for one implementation).
33
+
34
+ Using Faraday makes it easy to add Middleware. As an example, our flagship Rails app that powers watermark.org uses the following configuration in Production, which provides us with instrumentation through statsd, logging, and caching:
35
+ ```rb
36
+ config.connection = Faraday.new do |builder|
37
+ builder.use :http_cache,
38
+ shared_cache: false,
39
+ store: ActiveSupport::Cache::MemoryStore.new(size: 512.megabytes),
40
+ logger: Rails.logger,
41
+ serializer: Marshal,
42
+ instrumenter: ActiveSupport::Notifications
43
+
44
+ builder.use :gzip
45
+ builder.response :logger, Rails.logger, headers: false, bodies: false if Rails.env.development?
46
+ builder.request :instrumentation
47
+ builder.adapter :typhoeus
48
+ end
49
+ ```
50
+
51
+ #### At the Entry level
52
+
53
+ Our stack has three layers, the middle layer being essentially a cache for individual Entry hashes parsed out of responses from the Delivery API. We were able to add a caching layer here which stores entries retrieved over the Sync API, and responds to queries with cached versions of local content when possible. We consider this to be our best innovation on the Contentful ruby stack.
54
+
55
+ We have successfully created caching layers using Memcached, Postgres, and an in-memory hash. The architecture allows other caching implementations to be created fairly easily, and we have a set of rspec specs that can verify that a cache store behaves appropriately. For more information, [see the documentation on the caching modes here](https://watermarkchurch.github.io/wcc-contentful/latest/wcc-contentful/WCC/Contentful/Store.html).
56
+
57
+ ### Better Rails Integration
58
+
59
+ When we initially got started with the Contentful ruby models, we encountered one problem that was more frustrating than all others: If a field exists in the content model, but the particular entry we're working with does not have that field populated, then accessing that field raised a `NoMethodError`. This caused us to litter our code with `if defined?(entry.my_field)` which is bad practice. (Note: this has since been fixed in contentful.rb v2).
60
+
61
+ We decided it was better to not rely on `method_missing?` (what contentful.rb does), and instead to use `define_method` in an initializer to generate the methods for our models. This has the advantage that calling `.instance_methods` on a model class includes all the fields present in the content model.
62
+
63
+ We also took advantage of Rails' naming conventions to automatically infer the content type name based on the class name. Thus in our code, we have `app/models/page.rb` which defines `class Page << WCC::Contentful::Model::Page`, and is automatically linked to the `page` content type ID. (Note: this is overridable on a per-model basis)
64
+
65
+ All our models are automatically generated at startup which improves response times at the expense of initialization time. In addition, our content model registry allows easy definition of custom models in your `app/models` directory to override fields. This plays nice with other gems like algoliasearch-rails, which allows you to declaratively manage your Algolia indexes. Another example from our flagship watermark.org:
66
+
67
+ ```rb
68
+ class Page < WCC::Contentful::Model::Page
69
+ include AlgoliaSearch
70
+
71
+ algoliasearch(index_name: 'pages') do
72
+ attribute(:title, :slug)
73
+ ...
74
+ end
75
+ ```
76
+
77
+ ### Automatic Pagination and Link Resolution
78
+
79
+ Using the `contentful_model` gem, calling `Page.all.load` does not give you all Page entries if there are more than 100. To get the next page you must call `.paginate` on the response. By contrast, `Page.find_all` in the `wcc-contentful` gem gives you a [Lazy Enumerator](https://ruby-doc.org/core-2.5.0/Enumerator/Lazy.html). As you iterate past the 100th entry, the enumerator will automatically fetch the next page. If you only enumerate 99 entries (say with `.take(99)`), then the second page will never be fetched.
80
+
81
+ Similarly, if your Page references an asset, say `hero_image`, that field returns a `Link` object rather than the actual `Asset`. You must either predefine how many links you need using `Page.load_children(3).all.load`, or detect that `hero_image` is a `Link` like `if @page.hero_image.is_a? Contentful::Link` and then call `.resolve` on the link. We found all of that to be too cumbersome when we are down in a nested partial view template that may be invoked from multiple places.
82
+
83
+ The `wcc-contentful` gem, by contrast, automatically resolves a link when accessing the associated attribute. So in our example above, `wcc-contentful` will **always** return a `WCC::Contentful::Asset` when calling `@page.hero_image`, even if it has to execute a query to cdn.contentful.com in order to fetch it.
84
+
85
+ Warning: This can easily lead to you exhausting your Contentful API quota if you do not carefully tune your cache, which you should be doing anyways! The default settings will use the Rails cache to try to cache these resolutions, but *you are ultimately responsible for how many queries you execute!*
86
+
87
+ ### Automatic webhook management
88
+
89
+ The `wcc-contentful` gem, just like `contentful_rails`, provides an Engine to be mounted in your Rails routes file. Unlike `contentful_rails`, if you also configure `wcc-contentful` with a Contentful Management Token and a public `app_url`, then on startup the `wcc-contentful` engine will reach out to the Contentful Management API and ensure that a webhook is configured to point to your app. This is one less devops burden on you, and plays very nicely in with Heroku review apps.
90
+
9
91
  ## Installation
10
92
 
11
93
  Add this line to your application's Gemfile:
@@ -21,17 +103,21 @@ gem 'wcc-contentful'
21
103
  ```
22
104
 
23
105
  And then execute:
106
+
24
107
  ```
25
- $ bundle
108
+ $ bundle
26
109
  ```
27
- Or install it yourself as:
110
+
111
+ Or install it yourself:
112
+
28
113
  ```
29
- $ gem install wcc-contentful
114
+ $ gem install wcc-contentful
30
115
  ```
31
116
 
32
117
  ## Configure
33
118
 
34
119
  Put this in an initializer:
120
+
35
121
  ```ruby
36
122
  # config/initializers/wcc_contentful.rb
37
123
  WCC::Contentful.configure do |config|
@@ -42,8 +128,8 @@ end
42
128
  WCC::Contentful.init!
43
129
  ```
44
130
 
45
- All configuration options can be found [in the rubydoc](https://www.rubydoc.info/gems/wcc-contentful/WCC/Contentful/Configuration) under
46
- {WCC::Contentful::Configuration}
131
+ All configuration options can be found [in the rubydoc under
132
+ WCC::Contentful::Configuration](https://watermarkchurch.github.io/wcc-contentful/latest/wcc-contentful/WCC/Contentful/Configuration)
47
133
 
48
134
  ## Usage
49
135
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module WCC
4
4
  module Contentful
5
- VERSION = '1.0.0-rc2'
5
+ VERSION = '1.0.0-rc3'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wcc-contentful
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.pre.rc2
4
+ version: 1.0.0.pre.rc3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Watermark Dev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-10 00:00:00.000000000 Z
11
+ date: 2021-03-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: byebug
@@ -525,26 +525,114 @@ specification_version: 4
525
525
  summary: '[![Gem Version](https://badge.fury.io/rb/wcc-contentful.svg)](https://rubygems.org/gems/wcc-contentful)
526
526
  [![Build Status](https://travis-ci.org/watermarkchurch/wcc-contentful.svg?branch=master)](https://travis-ci.org/watermarkchurch/wcc-contentful)
527
527
  [![Coverage Status](https://coveralls.io/repos/github/watermarkchurch/wcc-contentful/badge.svg?branch=master)](https://coveralls.io/github/watermarkchurch/wcc-contentful?branch=master) Full
528
- documentation: https://www.rubydoc.info/gems/wcc-contentful # WCC::Contentful ##
529
- Installation Add this line to your application''s Gemfile: ```ruby gem ''wcc-contentful'',
530
- require: ''wcc/contentful/rails'' ``` If you''re not using rails, exclude the `require:`
531
- parameter. ```ruby gem ''wcc-contentful'' ``` And then execute: ``` $ bundle ```
532
- Or install it yourself as: ``` $ gem install wcc-contentful ``` ## Configure Put
533
- this in an initializer: ```ruby # config/initializers/wcc_contentful.rb WCC::Contentful.configure
534
- do |config| config.access_token = <CONTENTFUL_ACCESS_TOKEN> config.space = <CONTENTFUL_SPACE_ID>
535
- end WCC::Contentful.init! ``` All configuration options can be found [in the rubydoc](https://www.rubydoc.info/gems/wcc-contentful/WCC/Contentful/Configuration)
536
- under {WCC::Contentful::Configuration} ## Usage ### WCC::Contentful::Model API The
537
- WCC::Contentful::Model API exposes Contentful data as a set of dynamically generated
538
- Ruby objects. These objects are based on the content types in your Contentful space. All
539
- these objects are generated by `WCC::Contentful.init!` The following examples show
540
- how to use this API to find entries of the `page` content type: ```ruby # Find
541
- objects by id WCC::Contentful::Model::Page.find(''1E2ucWSdacxxf233sfa3'') # => #<WCC::Contentful::Model::Page:0x0000000005c71a78
542
- @created_at=2018-04-16 18:41:17 UTC...> # Find objects by field WCC::Contentful::Model::Page.find_by(slug:
543
- ''/some-slug'') # => #<WCC::Contentful::Model::Page:0x0000000005c71a78 @created_at=2018-04-16
544
- 18:41:17 UTC...> # Use operators to filter by a field # must use full notation
545
- for sys attributes (except ID) WCC::Contentful::Model::Page.find_all(''sys.created_at''
546
- => { lte: Date.today }) # => [#<WCC::Contentful::Model::Page:0x0000000005c71a78
547
- @created_at=2018-04-16 18:41:17 UTC...>, ... ] # Nest queries to mimick joins WCC::Contentful::Model::Page.find_by(subpages:
528
+ documentation: https://watermarkchurch.github.io/wcc-contentful/latest/wcc-contentful/ #
529
+ WCC::Contentful An alternative to Contentful''s [contentful.rb ruby client](https://github.com/contentful/contentful.rb/),
530
+ [contentful_model](https://github.com/contentful/contentful_model), and [contentful_rails](https://github.com/contentful/contentful_rails)
531
+ gems all in one. Table of Contents: 1. [Why?](#why-did-you-rewrite-the-contentful-ruby-stack)
532
+ 2. [Installation](#installation) ## Why did you rewrite the Contentful ruby stack? We
533
+ started working with Contentful almost 3 years ago. Since that time, Contentful''s
534
+ ruby stack has improved, but there are still a number of pain points that we feel
535
+ we have addressed better with our gem. These are: * [Low-level caching](#low-level-caching)
536
+ * [Better integration with Rails & Rails models](#better-rails-integration) * [Automatic
537
+ pagination and Automatic link resolution](#automatic-pagination-and-link-resolution)
538
+ * [Automatic webhook management](#automatic-webhook-management) Our gem no longer
539
+ depends on any of the Contentful gems and interacts directly with the [Contentful
540
+ CDA](https://www.contentful.com/developers/docs/references/content-delivery-api/)
541
+ and [Content Management API](https://www.contentful.com/developers/docs/references/content-management-api/)
542
+ over HTTPS. ### Low-level caching The wcc-contentful gem enables caching at two
543
+ levels: the HTTP response using [Faraday HTTP cache middleware](https://github.com/sourcelevel/faraday-http-cache),
544
+ and at the Entry level using the Rails cache and the [Sync API](https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/synchronization)
545
+ to keep it up to date. We''ve found these two cache layers to be very effective
546
+ at reducing both round trip latency to the Content Delivery API, as well as reducing
547
+ our monthly API request usage. (which reduces our overage charges. Hooray!) ####
548
+ At the request/response level By default, the contentful.rb gem requires the [HTTP
549
+ library](https://rubygems.org/gems/http). While simple and straightforward to use,
550
+ it is not as powerful for caching. We decided to make our client conform to the
551
+ [Faraday gem''s API](https://github.com/lostisland/faraday). If you prefer not
552
+ to use Faraday, you can choose to supply your own HTTP adapter that "quacks like"
553
+ Faraday (see the [TyphoeusAdapter](https://github.com/watermarkchurch/wcc-contentful/blob/master/wcc-contentful/lib/wcc/contentful/simple_client/typhoeus_adapter.rb)
554
+ for one implementation). Using Faraday makes it easy to add Middleware. As an
555
+ example, our flagship Rails app that powers watermark.org uses the following configuration
556
+ in Production, which provides us with instrumentation through statsd, logging, and
557
+ caching: ```rb config.connection = Faraday.new do |builder| builder.use :http_cache,
558
+ shared_cache: false, store: ActiveSupport::Cache::MemoryStore.new(size: 512.megabytes),
559
+ logger: Rails.logger, serializer: Marshal, instrumenter: ActiveSupport::Notifications builder.use
560
+ :gzip builder.response :logger, Rails.logger, headers: false, bodies: false if Rails.env.development?
561
+ builder.request :instrumentation builder.adapter :typhoeus end ``` #### At the
562
+ Entry level Our stack has three layers, the middle layer being essentially a cache
563
+ for individual Entry hashes parsed out of responses from the Delivery API. We were
564
+ able to add a caching layer here which stores entries retrieved over the Sync API,
565
+ and responds to queries with cached versions of local content when possible. We
566
+ consider this to be our best innovation on the Contentful ruby stack. We have successfully
567
+ created caching layers using Memcached, Postgres, and an in-memory hash. The architecture
568
+ allows other caching implementations to be created fairly easily, and we have a
569
+ set of rspec specs that can verify that a cache store behaves appropriately. For
570
+ more information, [see the documentation on the caching modes here](https://watermarkchurch.github.io/wcc-contentful/latest/wcc-contentful/WCC/Contentful/Store.html). ###
571
+ Better Rails Integration When we initially got started with the Contentful ruby
572
+ models, we encountered one problem that was more frustrating than all others: If
573
+ a field exists in the content model, but the particular entry we''re working with
574
+ does not have that field populated, then accessing that field raised a `NoMethodError`. This
575
+ caused us to litter our code with `if defined?(entry.my_field)` which is bad practice. (Note:
576
+ this has since been fixed in contentful.rb v2). We decided it was better to not
577
+ rely on `method_missing?` (what contentful.rb does), and instead to use `define_method`
578
+ in an initializer to generate the methods for our models. This has the advantage
579
+ that calling `.instance_methods` on a model class includes all the fields present
580
+ in the content model. We also took advantage of Rails'' naming conventions to automatically
581
+ infer the content type name based on the class name. Thus in our code, we have
582
+ `app/models/page.rb` which defines `class Page << WCC::Contentful::Model::Page`,
583
+ and is automatically linked to the `page` content type ID. (Note: this is overridable
584
+ on a per-model basis) All our models are automatically generated at startup which
585
+ improves response times at the expense of initialization time. In addition, our
586
+ content model registry allows easy definition of custom models in your `app/models`
587
+ directory to override fields. This plays nice with other gems like algoliasearch-rails,
588
+ which allows you to declaratively manage your Algolia indexes. Another example
589
+ from our flagship watermark.org: ```rb class Page < WCC::Contentful::Model::Page
590
+ include AlgoliaSearch algoliasearch(index_name: ''pages'') do attribute(:title,
591
+ :slug) ... end ``` ### Automatic Pagination and Link Resolution Using the `contentful_model`
592
+ gem, calling `Page.all.load` does not give you all Page entries if there are more
593
+ than 100. To get the next page you must call `.paginate` on the response. By contrast,
594
+ `Page.find_all` in the `wcc-contentful` gem gives you a [Lazy Enumerator](https://ruby-doc.org/core-2.5.0/Enumerator/Lazy.html). As
595
+ you iterate past the 100th entry, the enumerator will automatically fetch the next
596
+ page. If you only enumerate 99 entries (say with `.take(99)`), then the second
597
+ page will never be fetched. Similarly, if your Page references an asset, say `hero_image`,
598
+ that field returns a `Link` object rather than the actual `Asset`. You must either
599
+ predefine how many links you need using `Page.load_children(3).all.load`, or detect
600
+ that `hero_image` is a `Link` like `if @page.hero_image.is_a? Contentful::Link`
601
+ and then call `.resolve` on the link. We found all of that to be too cumbersome
602
+ when we are down in a nested partial view template that may be invoked from multiple
603
+ places. The `wcc-contentful` gem, by contrast, automatically resolves a link when
604
+ accessing the associated attribute. So in our example above, `wcc-contentful` will
605
+ **always** return a `WCC::Contentful::Asset` when calling `@page.hero_image`, even
606
+ if it has to execute a query to cdn.contentful.com in order to fetch it. Warning:
607
+ This can easily lead to you exhausting your Contentful API quota if you do not carefully
608
+ tune your cache, which you should be doing anyways! The default settings will use
609
+ the Rails cache to try to cache these resolutions, but *you are ultimately responsible
610
+ for how many queries you execute!* ### Automatic webhook management The `wcc-contentful`
611
+ gem, just like `contentful_rails`, provides an Engine to be mounted in your Rails
612
+ routes file. Unlike `contentful_rails`, if you also configure `wcc-contentful`
613
+ with a Contentful Management Token and a public `app_url`, then on startup the `wcc-contentful`
614
+ engine will reach out to the Contentful Management API and ensure that a webhook
615
+ is configured to point to your app. This is one less devops burden on you, and
616
+ plays very nicely in with Heroku review apps. ## Installation Add this line to
617
+ your application''s Gemfile: ```ruby gem ''wcc-contentful'', require: ''wcc/contentful/rails''
618
+ ``` If you''re not using rails, exclude the `require:` parameter. ```ruby gem
619
+ ''wcc-contentful'' ``` And then execute: ``` $ bundle ``` Or install it yourself: ```
620
+ $ gem install wcc-contentful ``` ## Configure Put this in an initializer: ```ruby
621
+ # config/initializers/wcc_contentful.rb WCC::Contentful.configure do |config| config.access_token
622
+ = <CONTENTFUL_ACCESS_TOKEN> config.space = <CONTENTFUL_SPACE_ID> end WCC::Contentful.init!
623
+ ``` All configuration options can be found [in the rubydoc under WCC::Contentful::Configuration](https://watermarkchurch.github.io/wcc-contentful/latest/wcc-contentful/WCC/Contentful/Configuration) ##
624
+ Usage ### WCC::Contentful::Model API The WCC::Contentful::Model API exposes Contentful
625
+ data as a set of dynamically generated Ruby objects. These objects are based on
626
+ the content types in your Contentful space. All these objects are generated by
627
+ `WCC::Contentful.init!` The following examples show how to use this API to find
628
+ entries of the `page` content type: ```ruby # Find objects by id WCC::Contentful::Model::Page.find(''1E2ucWSdacxxf233sfa3'')
629
+ # => #<WCC::Contentful::Model::Page:0x0000000005c71a78 @created_at=2018-04-16 18:41:17
630
+ UTC...> # Find objects by field WCC::Contentful::Model::Page.find_by(slug: ''/some-slug'')
631
+ # => #<WCC::Contentful::Model::Page:0x0000000005c71a78 @created_at=2018-04-16 18:41:17
632
+ UTC...> # Use operators to filter by a field # must use full notation for sys attributes
633
+ (except ID) WCC::Contentful::Model::Page.find_all(''sys.created_at'' => { lte: Date.today
634
+ }) # => [#<WCC::Contentful::Model::Page:0x0000000005c71a78 @created_at=2018-04-16
635
+ 18:41:17 UTC...>, ... ] # Nest queries to mimick joins WCC::Contentful::Model::Page.find_by(subpages:
548
636
  { slug: ''/some-slug'' }) # => #<WCC::Contentful::Model::Page:0x0000000005c71a78
549
637
  @created_at=2018-04-16 18:41:17 UTC...> # Pass the preview flag to use the preview
550
638
  client (must have set preview_token config param) preview_redirect = WCC::Contentful::Model::Redirect.find_by({