wcc-contentful 1.0.8 → 1.1.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 +174 -9
- data/lib/wcc/contentful/instrumentation.rb +20 -2
- data/lib/wcc/contentful/link_visitor.rb +26 -30
- data/lib/wcc/contentful/middleware/store.rb +2 -1
- data/lib/wcc/contentful/model.rb +5 -122
- data/lib/wcc/contentful/model_api.rb +182 -0
- data/lib/wcc/contentful/model_builder.rb +10 -4
- data/lib/wcc/contentful/model_methods.rb +8 -10
- data/lib/wcc/contentful/model_singleton_methods.rb +6 -6
- data/lib/wcc/contentful/rspec.rb +7 -5
- data/lib/wcc/contentful/services.rb +59 -61
- data/lib/wcc/contentful/store/cdn_adapter.rb +2 -1
- data/lib/wcc/contentful/store/factory.rb +2 -6
- data/lib/wcc/contentful/store/query.rb +1 -1
- data/lib/wcc/contentful/store/rspec_examples/basic_store.rb +0 -18
- data/lib/wcc/contentful/sync_engine.rb +0 -1
- data/lib/wcc/contentful/test/attributes.rb +0 -4
- data/lib/wcc/contentful/test/double.rb +4 -2
- data/lib/wcc/contentful/test/factory.rb +4 -2
- data/lib/wcc/contentful/version.rb +1 -1
- data/lib/wcc/contentful.rb +14 -8
- metadata +108 -33
data/lib/wcc/contentful.rb
CHANGED
@@ -34,7 +34,10 @@ module WCC::Contentful
|
|
34
34
|
# Gets the current configuration, after calling WCC::Contentful.configure
|
35
35
|
attr_reader :configuration
|
36
36
|
|
37
|
-
|
37
|
+
def types
|
38
|
+
ActiveSupport::Deprecation.warn('Use WCC::Contentful::Model.schema instead')
|
39
|
+
WCC::Contentful::Model.schema
|
40
|
+
end
|
38
41
|
|
39
42
|
# Gets all queryable locales.
|
40
43
|
# Reserved for future use.
|
@@ -91,7 +94,7 @@ module WCC::Contentful
|
|
91
94
|
end
|
92
95
|
end
|
93
96
|
|
94
|
-
|
97
|
+
content_types =
|
95
98
|
begin
|
96
99
|
if File.exist?(configuration.schema_file)
|
97
100
|
JSON.parse(File.read(configuration.schema_file))['contentTypes']
|
@@ -101,32 +104,35 @@ module WCC::Contentful
|
|
101
104
|
nil
|
102
105
|
end
|
103
106
|
|
104
|
-
if
|
107
|
+
if !content_types && %i[if_possible never].include?(configuration.update_schema_file)
|
105
108
|
# Final fallback - try to grab content types from CDN. We can't update the file
|
106
109
|
# because the CDN doesn't have all the field validation info, but we can at least
|
107
110
|
# build the WCC::Contentful::Model instances.
|
108
111
|
client = Services.instance.management_client ||
|
109
112
|
Services.instance.client
|
110
113
|
begin
|
111
|
-
|
114
|
+
content_types = client.content_types(limit: 1000).items if client
|
112
115
|
rescue WCC::Contentful::SimpleClient::ApiError => e
|
113
116
|
# indicates bad credentials
|
114
117
|
WCC::Contentful.logger.warn("Unable to load content types from API - #{e.message}")
|
115
118
|
end
|
116
119
|
end
|
117
120
|
|
118
|
-
unless
|
121
|
+
unless content_types
|
119
122
|
raise InitializationError, 'Unable to load content types from schema file or API!' \
|
120
123
|
' Check your access token and space ID.'
|
121
124
|
end
|
122
125
|
|
123
|
-
|
124
|
-
|
126
|
+
# Set the schema on the default WCC::Contentful::Model
|
127
|
+
WCC::Contentful::Model.configure(
|
128
|
+
configuration,
|
129
|
+
schema: WCC::Contentful::ContentTypeIndexer.from_json_schema(content_types).types,
|
130
|
+
services: WCC::Contentful::Services.instance
|
131
|
+
)
|
125
132
|
|
126
133
|
# Drop an initial sync
|
127
134
|
WCC::Contentful::SyncEngine::Job.perform_later if defined?(WCC::Contentful::SyncEngine::Job)
|
128
135
|
|
129
|
-
WCC::Contentful::ModelBuilder.new(@types).build_models
|
130
136
|
@configuration = @configuration.freeze
|
131
137
|
@initialized = true
|
132
138
|
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
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Watermark Dev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-02-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: byebug
|
@@ -455,6 +455,7 @@ files:
|
|
455
455
|
- lib/wcc/contentful/middleware/store.rb
|
456
456
|
- lib/wcc/contentful/middleware/store/caching_middleware.rb
|
457
457
|
- lib/wcc/contentful/model.rb
|
458
|
+
- lib/wcc/contentful/model_api.rb
|
458
459
|
- lib/wcc/contentful/model_builder.rb
|
459
460
|
- lib/wcc/contentful/model_methods.rb
|
460
461
|
- lib/wcc/contentful/model_singleton_methods.rb
|
@@ -495,7 +496,7 @@ homepage: https://github.com/watermarkchurch/wcc-contentful/wcc-contentful
|
|
495
496
|
licenses:
|
496
497
|
- MIT
|
497
498
|
metadata:
|
498
|
-
documentation_uri: https://watermarkchurch.github.io/wcc-contentful/1.
|
499
|
+
documentation_uri: https://watermarkchurch.github.io/wcc-contentful/1.1/wcc-contentful
|
499
500
|
post_install_message:
|
500
501
|
rdoc_options: []
|
501
502
|
require_paths:
|
@@ -525,17 +526,18 @@ summary: '[](https://
|
|
525
526
|
2. [Installation](#installation) 3. [Configuration](#configure) 4. [Usage](#usage)
|
526
527
|
1. [Model API](#wcccontentfulmodel-api) 2. [Store API](#store-api) 3. [Direct CDN
|
527
528
|
client](#direct-cdn-api-simpleclient) 4. [Accessing the APIs](#accessing-the-apis-within-application-code)
|
528
|
-
5. [Architecture](#architecture)
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
529
|
+
5. [Architecture](#architecture) 1. [Client Layer](#client-layer) 2. [Store Layer](#store-layer)
|
530
|
+
3. [Model Layer](#model-layer) 6. [Test Helpers](#test-helpers) 7. [Advanced Configuration
|
531
|
+
Example](#advanced-configuration-example) 8. [Connecting to Multiple Spaces](#connecting-to-multiple-spaces-or-environments)
|
532
|
+
9. [Development](#development) 10. [Contributing](#contributing) 11. [License](#license) ##
|
533
|
+
Why did you rewrite the Contentful ruby stack? We started working with Contentful
|
534
|
+
almost 3 years ago. Since that time, Contentful''s ruby stack has improved, but
|
535
|
+
there are still a number of pain points that we feel we have addressed better with
|
536
|
+
our gem. These are: * [Low-level caching](#low-level-caching) * [Better integration
|
537
|
+
with Rails & Rails models](#better-rails-integration) * [Automatic pagination and
|
538
|
+
Automatic link resolution](#automatic-pagination-and-link-resolution) * [Automatic
|
539
|
+
webhook management](#automatic-webhook-management) Our gem no longer depends on
|
540
|
+
any of the Contentful gems and interacts directly with the [Contentful CDA](https://www.contentful.com/developers/docs/references/content-delivery-api/)
|
539
541
|
and [Content Management API](https://www.contentful.com/developers/docs/references/content-management-api/)
|
540
542
|
over HTTPS. ### Low-level caching The wcc-contentful gem enables caching at two
|
541
543
|
levels: the HTTP response using [Faraday HTTP cache middleware](https://github.com/sourcelevel/faraday-http-cache),
|
@@ -552,7 +554,7 @@ summary: '[](https://
|
|
552
554
|
for one implementation). Using Faraday makes it easy to add Middleware. As an
|
553
555
|
example, our flagship Rails app that powers watermark.org uses the following configuration
|
554
556
|
in Production, which provides us with instrumentation through statsd, logging, and
|
555
|
-
caching: ```
|
557
|
+
caching: ```ruby config.connection = Faraday.new do |builder| builder.use :http_cache,
|
556
558
|
shared_cache: false, store: ActiveSupport::Cache::MemoryStore.new(size: 512.megabytes),
|
557
559
|
logger: Rails.logger, serializer: Marshal, instrumenter: ActiveSupport::Notifications builder.use
|
558
560
|
:gzip builder.response :logger, Rails.logger, headers: false, bodies: false if Rails.env.development?
|
@@ -584,7 +586,7 @@ summary: '[](https://
|
|
584
586
|
content model registry allows easy definition of custom models in your `app/models`
|
585
587
|
directory to override fields. This plays nice with other gems like algoliasearch-rails,
|
586
588
|
which allows you to declaratively manage your Algolia indexes. Another example
|
587
|
-
from our flagship watermark.org: ```
|
589
|
+
from our flagship watermark.org: ```ruby class Page < WCC::Contentful::Model::Page
|
588
590
|
include AlgoliaSearch algoliasearch(index_name: ''pages'') do attribute(:title,
|
589
591
|
:slug) ... end ``` ### Automatic Pagination and Link Resolution Using the `contentful_model`
|
590
592
|
gem, calling `Page.all.load` does not give you all Page entries if there are more
|
@@ -678,12 +680,55 @@ summary: '[](https://
|
|
678
680
|
gives access to the other configured services. You can also include the {WCC::Contentful::ServiceAccessors}
|
679
681
|
concern to define these services as attributes in a class. ```ruby class MyJob
|
680
682
|
< ApplicationJob include WCC::Contentful::ServiceAccessors def perform Page.find(...) store.find(...) client.entries(...)
|
681
|
-
end end ``` ## Architecture 
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
683
|
+
end end ``` ## Architecture  From
|
684
|
+
the bottom up: ### Client Layer The {WCC::Contentful::SimpleClient} provides methods
|
685
|
+
to access the [Contentful Content Delivery API](https://www.contentful.com/developers/docs/references/content-delivery-api/)
|
686
|
+
through your favorite HTTP client gem. The SimpleClient expects an Adapter that
|
687
|
+
conforms to the Faraday interface. Creating a SimpleClient to connect using different
|
688
|
+
credentials, or to connect without setting up all the rest of WCC::Contentful, is
|
689
|
+
easy: ```ruby WCC::Contentful::SimpleClient::Cdn.new( # required access_token:
|
690
|
+
''xxxx'', space: ''1234'', # optional environment: ''staging'', # omit to use master
|
691
|
+
default_locale: ''*'', rate_limit_wait_timeout: 10, instrumentation: ActiveSupport::Notifications,
|
692
|
+
connection: Faraday.new { |builder| ... }, ) ``` You can also create a {WCC::Contentful::SimpleClient::Preview}
|
693
|
+
to talk to the Preview API, or a {WCC::Contentful::SimpleClient::Management} to
|
694
|
+
talk to the Management API. ### Store Layer The Store Layer represents the data
|
695
|
+
store where Contentful entries are kept for querying. By default, `WCC::Contentful.init!`
|
696
|
+
creates a {WCC::Contentful::Store::CDNAdapter} which uses a {WCC::Contentful::SimpleClient::Cdn}
|
697
|
+
instance to query entries from the [Contentful Content Delivery API](https://www.contentful.com/developers/docs/references/content-delivery-api/). You
|
698
|
+
can also query entries from another source like Postgres or an in-memory hash if
|
699
|
+
your data is small enough. You can also implement your own store if you want! The
|
700
|
+
gem contains a suite of RSpec shared examples that give you a baseline for implementing
|
701
|
+
your own store. In your RSpec suite: ```ruby # frozen_string_literal: true require
|
702
|
+
''my_store'' require ''wcc/contentful/store/rspec_examples'' RSpec.describe MyStore
|
703
|
+
do it_behaves_like ''contentful store'', { # Set which store features your store
|
704
|
+
implements. nested_queries: true, # Does your store implement JOINs? include_param:
|
705
|
+
true # Does your store resolve links when given the :include option? } ``` The
|
706
|
+
store is kept up-to-date by the {WCC::Contentful::SyncEngine}. The `SyncEngine#next`
|
707
|
+
methodcalls the `#index` method on the configured store in order to update it with
|
708
|
+
the latest data via the [Contentful Sync API](https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/synchronization). For
|
709
|
+
example, the {WCC::Contentful::Store::MemoryStore} uses this to update the hash
|
710
|
+
with the newest version of an entry, or delete an entry out of the hash. #### Store
|
711
|
+
Middleware The store layer is made up of a base store (which implements {WCC::Contentful::Store::Interface}),
|
712
|
+
and optional middleware. The middleware allows custom transformation of received
|
713
|
+
entries via the `#select` and `#transform` methods. To create your own middleware
|
714
|
+
simply include {WCC::Contentful::Middleware::Store} and implement those methods,
|
715
|
+
then call `use` when configuring the store: ```ruby config.store :direct do use
|
716
|
+
MyMiddleware, param1: ''xxx'' end ``` The most useful middleware is the {WCC::Contentful::Middleware::Store::CachingMiddleware},
|
717
|
+
which enables `:lazy_sync` mode (see {WCC::Contentful::Configuration#store}) ###
|
718
|
+
Model Layer This is the global top layer where your Rails app looks up content
|
719
|
+
similarly to ActiveModel. The models are namespaced under the root class {WCC::Contentful::Model}.
|
720
|
+
Each model''s implementation of `.find`, `.find_by`, and `.find_all` simply call
|
721
|
+
into the configured Store. The main benefit of the Model layer is lazy link resolution. When
|
722
|
+
a model''s property is accessed, if that property is a link that has not been resolved
|
723
|
+
yet (for example using the `include: n` parameter on `.find_by`), the model will
|
724
|
+
automatically call `#find` on the store to resolve that linked entry. Note that
|
725
|
+
this can easily result in lots of CDN calls to Contentful! To optimize this you
|
726
|
+
should use the `include` parameter and/or use a different store. ## Test Helpers To
|
727
|
+
use the test helpers, include the following in your rails_helper.rb: ```ruby require
|
728
|
+
''wcc/contentful/rspec'' ``` This adds the following helpers to all your specs: ```ruby
|
729
|
+
## # Builds a in-memory instance of the Contentful model for the given content_type.
|
730
|
+
# All attributes that are known to be required fields on the content type # will
|
731
|
+
return a default value based on the field type. instance = contentful_create(''my-content-type'',
|
687
732
|
my_field: ''some-value'') # => #<WCC::Contentful::Model::MyContentType:0x0000000005c71a78
|
688
733
|
@created_at=2018-04-16 18:41:17 UTC...> instance.my_field # => "some-value" instance.other_required_field
|
689
734
|
# => "default-value" instance.other_optional_field # => nil instance.not_a_field
|
@@ -720,16 +765,46 @@ summary: '[](https://
|
|
720
765
|
\ -s $CONTENTFUL_SPACE_ID -a $CONTENTFUL_MANAGEMENT_TOKEN \ -y -p "$migrations_to_be_run" echo
|
721
766
|
"Updating schema file..." rake wcc_contentful:download_schema ``` All configuration
|
722
767
|
options can be found [in the rubydoc](https://www.rubydoc.info/gems/wcc-contentful/WCC/Contentful/Configuration)
|
723
|
-
under {WCC::Contentful::Configuration}
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
768
|
+
under {WCC::Contentful::Configuration} ## Connecting to multiple spaces or environments When
|
769
|
+
initializing the WCC::Contentful gem using `WCC::Contentful.init!`, the gem will
|
770
|
+
by default connect to the single Contentful space that you specify in the `WCC::Contentful.configure`
|
771
|
+
step. However the gem is also capable of connecting to multiple spaces within the
|
772
|
+
same ruby process! You just have to create and initialize a namespace. The {WCC::Contentful::ModelAPI}
|
773
|
+
concern makes this straightforward. Start by creating your Namespace and including
|
774
|
+
the concern: ```ruby # app/models/my_second_space.rb class MySecondSpace include
|
775
|
+
WCC::Contentful::ModelAPI end # app/models/other_page.rb class OtherPage < MySecondSpace::Page
|
776
|
+
end ``` Then configure it in an initializer: ```ruby # config/initializers/my_second_space.rb
|
777
|
+
MySecondSpace.configure do |config| # Make sure to point to a different schema file
|
778
|
+
from your first space! config.schema_file = Rails.root.join(''db/second-contentful-schema.json'') config.access_token
|
779
|
+
= ENV[''SECOND_CONTENTFUL_ACCESS_TOKEN''] config.preview_token = ENV[''SECOND_CONTENTFUL_PREVIEW_ACCESS_TOKEN'']
|
780
|
+
config.space = ENV[''SECOND_CONTENTFUL_SPACE_ID''] config.environment = ENV[''CONTENTFUL_ENVIRONMENT'']
|
781
|
+
end ``` Finally, use it: ```ruby OtherPage.find(''1234'') # GET https://cdn.contentful.com/spaces/other-space/environments/other-env/entries/1234
|
782
|
+
# => #<OtherPage:0x0000000005c71a78 @created_at=2018-04-16 18:41:17 UTC...> Page.find(''1234'')
|
783
|
+
# GET https://cdn.contentful.com/spaces/first-space/environments/first-env/entries/1234
|
784
|
+
# => #<Page:0x0000000001271b70 @created_at=2018-04-15 12:02:14 UTC...> ``` The
|
785
|
+
ModelAPI defines a second stack of services that you can access for lower level
|
786
|
+
connections: ```ruby store = MySecondSpace.services.store # => #<WCC::Contentful::Store::CDNAdapter:0x00007f888edac118
|
787
|
+
client = MySecondSpace.services.client # => #<WCC::Contentful::SimpleClient::Cdn:0x00007f88942a8888
|
788
|
+
preview_client = MySecondSpace.services.preview_client # => #<WCC::Contentful::SimpleClient::Preview:0x00007f888ccafa00
|
789
|
+
sync_engine = MySecondSpace.services.sync_engine # => #<WCC::Contentful::SyncEngine:0x00007f88960b6b40
|
790
|
+
``` Note that the above services are not accessible on {WCC::Contentful::Services.instance}
|
791
|
+
or via the {WCC::Contentful::ServiceAccessors}. ### Using a sync store with a second
|
792
|
+
space If you use something other than the CDNAdapter with your second space, you
|
793
|
+
will need to find a way to trigger `MySecondSpace.services.sync_engine.next` to
|
794
|
+
keep it up-to-date. The {WCC::Contentful::Engine} will only manage the global SyncEngine
|
795
|
+
configured by the global {WCC::Contentful.configure}. The easiest way to do this
|
796
|
+
is to set up your own Rails route to respond to Contentful webhooks and then configure
|
797
|
+
the second Contentful space to send webhooks to this route. You could also do this
|
798
|
+
by triggering it periodically in a background job using Sidekiq and [sidekiq-scheduler](https://github.com/Moove-it/sidekiq-scheduler). ##
|
799
|
+
Development After checking out the repo, run `bin/setup` to install dependencies.
|
800
|
+
Then, run `bundle exec rspec` to run the tests. You can also run `bin/console` for
|
801
|
+
an interactive prompt that will allow you to experiment. ## Contributing Bug reports
|
802
|
+
and pull requests are welcome on GitHub at https://github.com/watermarkchurch/wcc-contentful. The
|
803
|
+
developers at Watermark Community Church have pledged to govern their interactions
|
804
|
+
with each other, with their clients, and with the larger wcc-contentful user community
|
805
|
+
in accordance with the "instruments of good works" from chapter 4 of The Rule of
|
806
|
+
St. Benedict (hereafter: "The Rule"). This code of ethics has proven its mettle
|
807
|
+
in thousands of diverse communities for over 1,500 years, and has served as a baseline
|
808
|
+
for many civil law codes since the time of Charlemagne. [See the full Code of Ethics](https://github.com/watermarkchurch/wcc-contentful/blob/master/CODE_OF_ETHICS.md) ##
|
734
809
|
License The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).'
|
735
810
|
test_files: []
|