wcc-contentful 1.3.0 → 1.4.0.rc1

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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +105 -14
  3. data/lib/wcc/contentful/configuration.rb +12 -5
  4. data/lib/wcc/contentful/downloads_schema.rb +14 -2
  5. data/lib/wcc/contentful/entry_locale_transformer.rb +107 -0
  6. data/lib/wcc/contentful/exceptions.rb +5 -0
  7. data/lib/wcc/contentful/link_visitor.rb +12 -1
  8. data/lib/wcc/contentful/middleware/store/caching_middleware.rb +25 -8
  9. data/lib/wcc/contentful/middleware/store/locale_middleware.rb +30 -0
  10. data/lib/wcc/contentful/middleware/store.rb +20 -16
  11. data/lib/wcc/contentful/model_api.rb +2 -2
  12. data/lib/wcc/contentful/model_builder.rb +9 -2
  13. data/lib/wcc/contentful/model_methods.rb +4 -6
  14. data/lib/wcc/contentful/simple_client/cdn.rb +5 -2
  15. data/lib/wcc/contentful/simple_client/management.rb +16 -0
  16. data/lib/wcc/contentful/simple_client.rb +1 -0
  17. data/lib/wcc/contentful/store/base.rb +6 -1
  18. data/lib/wcc/contentful/store/cdn_adapter.rb +13 -4
  19. data/lib/wcc/contentful/store/factory.rb +8 -1
  20. data/lib/wcc/contentful/store/memory_store.rb +27 -8
  21. data/lib/wcc/contentful/store/postgres_store.rb +4 -3
  22. data/lib/wcc/contentful/store/query/condition.rb +89 -0
  23. data/lib/wcc/contentful/store/query.rb +9 -35
  24. data/lib/wcc/contentful/store/rspec_examples/basic_store.rb +84 -12
  25. data/lib/wcc/contentful/store/rspec_examples/locale_queries.rb +220 -0
  26. data/lib/wcc/contentful/store/rspec_examples/operators/eq.rb +1 -1
  27. data/lib/wcc/contentful/store/rspec_examples.rb +13 -1
  28. data/lib/wcc/contentful/sync_engine.rb +1 -1
  29. data/lib/wcc/contentful/test/double.rb +1 -1
  30. data/lib/wcc/contentful/test/factory.rb +2 -4
  31. data/lib/wcc/contentful/version.rb +1 -1
  32. data/lib/wcc/contentful.rb +17 -6
  33. metadata +112 -62
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.3.0
4
+ version: 1.4.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Watermark Dev
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-19 00:00:00.000000000 Z
11
+ date: 2023-02-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: byebug
@@ -429,6 +429,7 @@ files:
429
429
  - lib/wcc/contentful/content_type_indexer.rb
430
430
  - lib/wcc/contentful/downloads_schema.rb
431
431
  - lib/wcc/contentful/engine.rb
432
+ - lib/wcc/contentful/entry_locale_transformer.rb
432
433
  - lib/wcc/contentful/event.rb
433
434
  - lib/wcc/contentful/events.rb
434
435
  - lib/wcc/contentful/exceptions.rb
@@ -440,6 +441,7 @@ files:
440
441
  - lib/wcc/contentful/middleware.rb
441
442
  - lib/wcc/contentful/middleware/store.rb
442
443
  - lib/wcc/contentful/middleware/store/caching_middleware.rb
444
+ - lib/wcc/contentful/middleware/store/locale_middleware.rb
443
445
  - lib/wcc/contentful/model.rb
444
446
  - lib/wcc/contentful/model_api.rb
445
447
  - lib/wcc/contentful/model_builder.rb
@@ -469,10 +471,12 @@ files:
469
471
  - lib/wcc/contentful/store/postgres_store/schema_1.sql
470
472
  - lib/wcc/contentful/store/postgres_store/schema_2.sql
471
473
  - lib/wcc/contentful/store/query.rb
474
+ - lib/wcc/contentful/store/query/condition.rb
472
475
  - lib/wcc/contentful/store/query/interface.rb
473
476
  - lib/wcc/contentful/store/rspec_examples.rb
474
477
  - lib/wcc/contentful/store/rspec_examples/basic_store.rb
475
478
  - lib/wcc/contentful/store/rspec_examples/include_param.rb
479
+ - lib/wcc/contentful/store/rspec_examples/locale_queries.rb
476
480
  - lib/wcc/contentful/store/rspec_examples/nested_queries.rb
477
481
  - lib/wcc/contentful/store/rspec_examples/operators.rb
478
482
  - lib/wcc/contentful/store/rspec_examples/operators/eq.rb
@@ -491,9 +495,9 @@ homepage: https://github.com/watermarkchurch/wcc-contentful/wcc-contentful
491
495
  licenses:
492
496
  - MIT
493
497
  metadata:
494
- documentation_uri: https://watermarkchurch.github.io/wcc-contentful/1.3/wcc-contentful
498
+ documentation_uri: https://watermarkchurch.github.io/wcc-contentful/1.4/wcc-contentful
495
499
  rubygems_mfa_required: 'true'
496
- post_install_message:
500
+ post_install_message:
497
501
  rdoc_options: []
498
502
  require_paths:
499
503
  - lib
@@ -504,12 +508,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
504
508
  version: '2.7'
505
509
  required_rubygems_version: !ruby/object:Gem::Requirement
506
510
  requirements:
507
- - - ">="
511
+ - - ">"
508
512
  - !ruby/object:Gem::Version
509
- version: '0'
513
+ version: 1.3.1
510
514
  requirements: []
511
- rubygems_version: 3.1.6
512
- signing_key:
515
+ rubygems_version: 3.3.7
516
+ signing_key:
513
517
  specification_version: 4
514
518
  summary: '[![Gem Version](https://badge.fury.io/rb/wcc-contentful.svg)](https://rubygems.org/gems/wcc-contentful)
515
519
  [![Build Status](https://circleci.com/gh/watermarkchurch/wcc-contentful.svg?style=svg)](https://circleci.com/gh/watermarkchurch/wcc-contentful)
@@ -526,7 +530,7 @@ summary: '[![Gem Version](https://badge.fury.io/rb/wcc-contentful.svg)](https://
526
530
  Example](#advanced-configuration-example) 8. [Connecting to Multiple Spaces](#connecting-to-multiple-spaces-or-environments)
527
531
  9. [Development](#development) 10. [Contributing](#contributing) 11. [License](#license) ##
528
532
  Why did you rewrite the Contentful ruby stack? We started working with Contentful
529
- almost 3 years ago. Since that time, Contentful''s ruby stack has improved, but
533
+ almost 5 years ago. Since that time, Contentful''s ruby stack has improved, but
530
534
  there are still a number of pain points that we feel we have addressed better with
531
535
  our gem. These are: * [Low-level caching](#low-level-caching) * [Better integration
532
536
  with Rails & Rails models](#better-rails-integration) * [Automatic pagination and
@@ -620,19 +624,22 @@ summary: '[![Gem Version](https://badge.fury.io/rb/wcc-contentful.svg)](https://
620
624
  data as a set of dynamically generated Ruby objects. These objects are based on
621
625
  the content types in your Contentful space. All these objects are generated by
622
626
  `WCC::Contentful.init!` The following examples show how to use this API to find
623
- entries of the `page` content type: ```ruby # Find objects by id WCC::Contentful::Model::Page.find(''1E2ucWSdacxxf233sfa3'')
624
- # => #<WCC::Contentful::Model::Page:0x0000000005c71a78 @created_at=2018-04-16 18:41:17
625
- UTC...> # Find objects by field WCC::Contentful::Model::Page.find_by(slug: ''/some-slug'')
626
- # => #<WCC::Contentful::Model::Page:0x0000000005c71a78 @created_at=2018-04-16 18:41:17
627
- UTC...> # Use operators to filter by a field # must use full notation for sys attributes
628
- (except ID) WCC::Contentful::Model::Page.find_all(''sys.created_at'' => { lte: Date.today
629
- }) # => [#<WCC::Contentful::Model::Page:0x0000000005c71a78 @created_at=2018-04-16
630
- 18:41:17 UTC...>, ... ] # Nest queries to mimick joins WCC::Contentful::Model::Page.find_by(subpages:
631
- { slug: ''/some-slug'' }) # => #<WCC::Contentful::Model::Page:0x0000000005c71a78
632
- @created_at=2018-04-16 18:41:17 UTC...> # Pass the preview flag to use the preview
633
- client (must have set preview_token config param) preview_redirect = WCC::Contentful::Model::Redirect.find_by({
634
- slug: ''draft-redirect'' }, preview: true) # => #<WCC::Contentful::Model::Redirect:0x0000000005d879ad
635
- @created_at=2018-04-16 18:41:17 UTC...> preview_redirect_object.href # => ''http://www.somesite.com/slug-for-redirect''
627
+ entries of the `page` content type: ```ruby # app/models/page.rb class Page < WCC::Contentful::Model::Page #
628
+ You can add additional methods here end # Find objects by id Page.find(''1E2ucWSdacxxf233sfa3'')
629
+ # => #<Page:0x0000000005c71a78 @created_at=2018-04-16 18:41:17 UTC...> # Find objects
630
+ by field Page.find_by(slug: ''/some-slug'') # => #<Page:0x0000000005c71a78 @created_at=2018-04-16
631
+ 18:41:17 UTC...> # Use operators to filter by a field # must use full notation
632
+ for sys attributes (except ID) Page.find_all(''sys.created_at'' => { lte: Date.today
633
+ }) # => [#<Page:0x0000000005c71a78 @created_at=2018-04-16 18:41:17 UTC...>, ...
634
+ ] # Nest queries to mimick joins Page.find_by(subpages: { slug: ''/some-slug''
635
+ }) # => #<Page:0x0000000005c71a78 @created_at=2018-04-16 18:41:17 UTC...> # Fetch
636
+ an entry in a different locale spanish_homepage = Page.find_by(slug: ''/'', options:
637
+ { locale: ''es-US'' }) # => #<Page:0x0000000005c71a78 @created_at=2018-04-16 18:41:17
638
+ UTC...> spanish_homepage.title # => Esta es la página principal # Pass the preview
639
+ flag to use the preview client (must have set preview_token config param) preview_redirect
640
+ = WCC::Contentful::Model::Redirect.find_by({ slug: ''draft-redirect'' }, preview:
641
+ true) # => #<WCC::Contentful::Model::Redirect:0x0000000005d879ad @created_at=2018-04-16
642
+ 18:41:17 UTC...> preview_redirect_object.href # => ''http://www.somesite.com/slug-for-redirect''
636
643
  ``` See the {WCC::Contentful::Model} documentation for more details. ### Store
637
644
  API The Store layer is used by the Model API to access Contentful data in a raw
638
645
  form. The Store layer returns entries as hashes parsed from JSON, conforming to
@@ -643,12 +650,20 @@ summary: '[![Gem Version](https://badge.fury.io/rb/wcc-contentful.svg)](https://
643
650
  filter: { slug: ''/some-slug'' }) # => {"sys"=> # ... # "fields"=> # ...} query
644
651
  = store.find_all(content_type: ''page'').eq(''group'', ''some-group'') # => #<WCC::Contentful::Store::CDNAdapter::Query:0x00007fa3d40b84f0
645
652
  query.first # => {"sys"=> # ... # "fields"=> # ...} query.result # => #<Enumerator::Lazy:
646
- ...> query.result.force # => [{"sys"=> ...}, {"sys"=> ...}, ...] ``` See the {WCC::Contentful::Store}
647
- documentation for more details. ### Direct CDN API (SimpleClient) The SimpleClient
648
- is the bottom layer, and is used to get raw data directly from the Contentful CDN. It
649
- handles response parsing and paging, but does not resolve links or transform the
650
- result into a Model class. The following examples show how to use the SimpleClient
651
- to retrieve data directly from the Contentful CDN: ```ruby client = WCC::Contentful::Services.instance.client
653
+ ...> query.result.force # => [{"sys"=> ...}, {"sys"=> ...}, ...] ``` The store
654
+ layer, while superficially similar to the Contentful API, tries to present a different
655
+ "View" over the data which is more compatible with the Model layer. It resolves
656
+ includes by actually replacing the in-memory `Link` objects with their linked `Entry`
657
+ representations. This lets you traverse the links naturally using `#dig` or `#[]`: ```ruby
658
+ # Include to a depth of 3 to make sure it''s included homepage = store.find_by(slug:
659
+ ''/'', include: 3) # Traverse through the top nav menu => menu button 0 => about
660
+ page about_page = homepage.dig(''fields'', ''nav_menu'', ''fields'', ''buttons'',
661
+ 0, ''fields'', ''page'') ``` See the {WCC::Contentful::Store} documentation for
662
+ more details. ### Direct CDN API (SimpleClient) The SimpleClient is the bottom
663
+ layer, and is used to get raw data directly from the Contentful CDN. It handles
664
+ response parsing and paging, but does not resolve links or transform the result
665
+ into a Model class. The following examples show how to use the SimpleClient to
666
+ retrieve data directly from the Contentful CDN: ```ruby client = WCC::Contentful::Services.instance.client
652
667
  # => #<WCC::Contentful::SimpleClient::Cdn:0x00007fa3cde89310 response = client.entry(''5FsqsbMECsM62e04U8sY4Y'')
653
668
  # => #<WCC::Contentful::SimpleClient::Response:0x00007fa3d103a4e0 response.body
654
669
  # => "{\n \"sys\": {\n ... response.raw # => {"sys"=> # ... # "fields"=> # ...} client.asset(''5FsqsbMECsM62e04U8sY4Y'').raw
@@ -704,27 +719,44 @@ summary: '[![Gem Version](https://badge.fury.io/rb/wcc-contentful.svg)](https://
704
719
  example, the {WCC::Contentful::Store::MemoryStore} uses this to update the hash
705
720
  with the newest version of an entry, or delete an entry out of the hash. #### Store
706
721
  Middleware The store layer is made up of a base store (which implements {WCC::Contentful::Store::Interface}),
707
- and optional middleware. The middleware allows custom transformation of received
708
- entries via the `#select` and `#transform` methods. To create your own middleware
709
- simply include {WCC::Contentful::Middleware::Store} and implement those methods,
710
- then call `use` when configuring the store: ```ruby config.store :direct do use
711
- MyMiddleware, param1: ''xxx'' end ``` The most useful middleware is the {WCC::Contentful::Middleware::Store::CachingMiddleware},
712
- which enables `:lazy_sync` mode (see {WCC::Contentful::Configuration#store}) ###
713
- Model Layer This is the global top layer where your Rails app looks up content
714
- similarly to ActiveModel. The models are namespaced under the root class {WCC::Contentful::Model}.
715
- Each model''s implementation of `.find`, `.find_by`, and `.find_all` simply call
716
- into the configured Store. The main benefit of the Model layer is lazy link resolution. When
717
- a model''s property is accessed, if that property is a link that has not been resolved
718
- yet (for example using the `include: n` parameter on `.find_by`), the model will
719
- automatically call `#find` on the store to resolve that linked entry. Note that
720
- this can easily result in lots of CDN calls to Contentful! To optimize this you
721
- should use the `include` parameter and/or use a different store. ## Test Helpers To
722
- use the test helpers, include the following in your rails_helper.rb: ```ruby require
723
- ''wcc/contentful/rspec'' ``` This adds the following helpers to all your specs: ```ruby
724
- ## # Builds a in-memory instance of the Contentful model for the given content_type.
725
- # All attributes that are known to be required fields on the content type # will
726
- return a default value based on the field type. instance = contentful_create(''my-content-type'',
727
- my_field: ''some-value'') # => #<WCC::Contentful::Model::MyContentType:0x0000000005c71a78
722
+ and some required middleware. The list of default middleware applied to each store
723
+ is found in {WCC::Contentful::Store::Factory.default_middleware} To create your
724
+ own middleware simply include {WCC::Contentful::Middleware::Store}. Then you can
725
+ optionally implement the `#transform` and `#select?` methods: ```ruby class MyMiddleware
726
+ include WCC::Contentful::Middleware::Store # Called for each entry that is requested
727
+ out of the backing store. You can modify the entry and return it to the # next
728
+ layer. def transform(entry, options) # Do something with the entry... # Make sure
729
+ you return it at the end! entry end def select?(entry, options) # Choose whether
730
+ this entry should exist or not. If you return false here, then the entry will act
731
+ as though it # were archived in Contentful. entry.dig(''fields'', ''hide_until'')
732
+ > Time.zone.now end end ``` You can also override any of the standard Store methods. To
733
+ apply the middleware, call `use` when configuring the store: ```ruby config.store
734
+ :direct do use MyMiddleware, param1: ''xxx'' end ``` The most useful middleware
735
+ is the {WCC::Contentful::Middleware::Store::CachingMiddleware}, which enables `:lazy_sync`
736
+ mode (see {WCC::Contentful::Configuration#store}) ### Model Layer This is the
737
+ global top layer where your Rails app looks up content similarly to ActiveModel. The
738
+ models are namespaced under the root class {WCC::Contentful::Model}. Each model''s
739
+ implementation of `.find`, `.find_by`, and `.find_all` simply call into the configured
740
+ Store. Models can be initialized directly with the `.new` method, by passing in
741
+ a hash: ```ruby entry = { ''sys'' => ..., ''fields'' => ... } Page.new(entry) ``` **The
742
+ initializer must receive a localized entry**. An entry found using a `locale=*`
743
+ query must be transformed to a localized entry using the {WCC::Contentful::EntryLocaleTransformer}
744
+ before passing it to your model: ```ruby entry = client.entry(''1234'', locale:
745
+ ''*'').raw localized_entry = WCC::Contentful::EntryLocaleTransformer.transform_to_locale(entry,
746
+ ''en-US'') Page.new(localized_entry) ``` The Store layer ensures that localized
747
+ entries are returned using the {WCC::Contentful::Middleware::Store::LocaleMiddleware}. The
748
+ main benefit of the Model layer is lazy link resolution. When a model''s property
749
+ is accessed, if that property is a link that has not been resolved yet (for example
750
+ using the `include: n` parameter on `.find_by`), the model will automatically call
751
+ `#find` on the store to resolve that linked entry. Note that this can easily result
752
+ in lots of CDN calls to Contentful! To optimize this you should use the `include`
753
+ parameter and/or use a different store. ## Test Helpers To use the test helpers,
754
+ include the following in your rails_helper.rb: ```ruby require ''wcc/contentful/rspec''
755
+ ``` This adds the following helpers to all your specs: ```ruby ## # Builds a in-memory
756
+ instance of the Contentful model for the given content_type. # All attributes that
757
+ are known to be required fields on the content type # will return a default value
758
+ based on the field type. instance = contentful_create(''my-content-type'', my_field:
759
+ ''some-value'') # => #<WCC::Contentful::Model::MyContentType:0x0000000005c71a78
728
760
  @created_at=2018-04-16 18:41:17 UTC...> instance.my_field # => "some-value" instance.other_required_field
729
761
  # => "default-value" instance.other_optional_field # => nil instance.not_a_field
730
762
  # NoMethodError: undefined method `not_a_field'' for #<MyContentType:0x00007fbac81ee490> ##
@@ -766,14 +798,19 @@ summary: '[![Gem Version](https://badge.fury.io/rb/wcc-contentful.svg)](https://
766
798
  step. However the gem is also capable of connecting to multiple spaces within the
767
799
  same ruby process! You just have to create and initialize a namespace. The {WCC::Contentful::ModelAPI}
768
800
  concern makes this straightforward. Start by creating your Namespace and including
769
- the concern: ```ruby # app/models/my_second_space.rb class MySecondSpace include
770
- WCC::Contentful::ModelAPI end # app/models/other_page.rb class OtherPage < MySecondSpace::Page
771
- end ``` Then configure it in an initializer: ```ruby # config/initializers/my_second_space.rb
801
+ the concern: ```ruby # lib/my_second_space.rb # Note: This class must be in the
802
+ "lib" folder in :zeitwerk mode, otherwise Rails 6+ will unload all your constants
803
+ # that were created in the initializer. Your models which subclass this namespace
804
+ may reside in the app/models directory. class MySecondSpace include WCC::Contentful::ModelAPI
805
+ end # app/models/other_page.rb class OtherPage < MySecondSpace::Page end ``` Then
806
+ configure it in an initializer: ```ruby # config/initializers/my_second_space.rb
772
807
  MySecondSpace.configure do |config| # Make sure to point to a different schema file
773
808
  from your first space! config.schema_file = Rails.root.join(''db/second-contentful-schema.json'') config.access_token
774
809
  = ENV[''SECOND_CONTENTFUL_ACCESS_TOKEN''] config.preview_token = ENV[''SECOND_CONTENTFUL_PREVIEW_ACCESS_TOKEN'']
775
810
  config.space = ENV[''SECOND_CONTENTFUL_SPACE_ID''] config.environment = ENV[''CONTENTFUL_ENVIRONMENT'']
776
- end ``` Finally, use it: ```ruby OtherPage.find(''1234'') # GET https://cdn.contentful.com/spaces/other-space/environments/other-env/entries/1234
811
+ end # Ensure that models are reloaded in Rails development mode Rails.application.config.to_prepare
812
+ do MySecondSpace.reload! end ``` Finally, use it: ```ruby OtherPage.find(''1234'')
813
+ # GET https://cdn.contentful.com/spaces/other-space/environments/other-env/entries/1234
777
814
  # => #<OtherPage:0x0000000005c71a78 @created_at=2018-04-16 18:41:17 UTC...> Page.find(''1234'')
778
815
  # GET https://cdn.contentful.com/spaces/first-space/environments/first-env/entries/1234
779
816
  # => #<Page:0x0000000001271b70 @created_at=2018-04-15 12:02:14 UTC...> ``` The
@@ -783,14 +820,27 @@ summary: '[![Gem Version](https://badge.fury.io/rb/wcc-contentful.svg)](https://
783
820
  preview_client = MySecondSpace.services.preview_client # => #<WCC::Contentful::SimpleClient::Preview:0x00007f888ccafa00
784
821
  sync_engine = MySecondSpace.services.sync_engine # => #<WCC::Contentful::SyncEngine:0x00007f88960b6b40
785
822
  ``` Note that the above services are not accessible on {WCC::Contentful::Services.instance}
786
- or via the {WCC::Contentful::ServiceAccessors}. ### Using a sync store with a second
787
- space If you use something other than the CDNAdapter with your second space, you
788
- will need to find a way to trigger `MySecondSpace.services.sync_engine.next` to
789
- keep it up-to-date. The {WCC::Contentful::Engine} will only manage the global SyncEngine
790
- configured by the global {WCC::Contentful.configure}. The easiest way to do this
791
- is to set up your own Rails route to respond to Contentful webhooks and then configure
792
- the second Contentful space to send webhooks to this route. You could also do this
793
- by triggering it periodically in a background job using Sidekiq and [sidekiq-scheduler](https://github.com/Moove-it/sidekiq-scheduler). ##
823
+ or via the {WCC::Contentful::ServiceAccessors}. #### Important Note when using
824
+ Zeitwerk with Rails 6+ When using Rails >= 6 with `config.autoloader = :zeitwerk`,
825
+ Rails will remove any models defined in `app/models` after initialization and then
826
+ load them again when they are referenced. If you `include WCC::Contentful::ModelAPI`
827
+ in a class defined inside the `app` directory, this will have the effect of deleting
828
+ all configuration that was set in the initializer as well as the constants generated
829
+ from your schema. This will result in one of two errors: * `NameError (uninitialized
830
+ constant MySecondSpace::MyContentType)` if you try to reference a subclass such
831
+ as `MyContentType < MySecondSpace::MyContentType` * `ArgumentError (Not yet configured!)`
832
+ if you try to `MySecondSpace.find(''xxxx'')` to load an Entry or Asset The solution
833
+ is to have your secondary namespace in a folder which is not in the `autoload_paths`.
834
+ We suggest using `lib`, which will work so long as you have not added the `lib`
835
+ folder to the `autoload_paths` as some uninformed StackOverflow answers suggest
836
+ you do. ### Using a sync store with a second space If you use something other
837
+ than the CDNAdapter with your second space, you will need to find a way to trigger
838
+ `MySecondSpace.services.sync_engine.next` to keep it up-to-date. The {WCC::Contentful::Engine}
839
+ will only manage the global SyncEngine configured by the global {WCC::Contentful.configure}. The
840
+ easiest way to do this is to set up your own Rails route to respond to Contentful
841
+ webhooks and then configure the second Contentful space to send webhooks to this
842
+ route. You could also do this by triggering it periodically in a background job
843
+ using Sidekiq and [sidekiq-scheduler](https://github.com/Moove-it/sidekiq-scheduler). ##
794
844
  Development After checking out the repo, run `bin/setup` to install dependencies.
795
845
  Then, run `bundle exec rspec` to run the tests. You can also run `bin/console` for
796
846
  an interactive prompt that will allow you to experiment. ## Contributing Bug reports