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.
- checksums.yaml +4 -4
- data/README.md +105 -14
- data/lib/wcc/contentful/configuration.rb +12 -5
- data/lib/wcc/contentful/downloads_schema.rb +14 -2
- data/lib/wcc/contentful/entry_locale_transformer.rb +107 -0
- data/lib/wcc/contentful/exceptions.rb +5 -0
- data/lib/wcc/contentful/link_visitor.rb +12 -1
- data/lib/wcc/contentful/middleware/store/caching_middleware.rb +25 -8
- data/lib/wcc/contentful/middleware/store/locale_middleware.rb +30 -0
- data/lib/wcc/contentful/middleware/store.rb +20 -16
- data/lib/wcc/contentful/model_api.rb +2 -2
- data/lib/wcc/contentful/model_builder.rb +9 -2
- data/lib/wcc/contentful/model_methods.rb +4 -6
- data/lib/wcc/contentful/simple_client/cdn.rb +5 -2
- data/lib/wcc/contentful/simple_client/management.rb +16 -0
- data/lib/wcc/contentful/simple_client.rb +1 -0
- data/lib/wcc/contentful/store/base.rb +6 -1
- data/lib/wcc/contentful/store/cdn_adapter.rb +13 -4
- data/lib/wcc/contentful/store/factory.rb +8 -1
- data/lib/wcc/contentful/store/memory_store.rb +27 -8
- data/lib/wcc/contentful/store/postgres_store.rb +4 -3
- data/lib/wcc/contentful/store/query/condition.rb +89 -0
- data/lib/wcc/contentful/store/query.rb +9 -35
- data/lib/wcc/contentful/store/rspec_examples/basic_store.rb +84 -12
- data/lib/wcc/contentful/store/rspec_examples/locale_queries.rb +220 -0
- data/lib/wcc/contentful/store/rspec_examples/operators/eq.rb +1 -1
- data/lib/wcc/contentful/store/rspec_examples.rb +13 -1
- data/lib/wcc/contentful/sync_engine.rb +1 -1
- data/lib/wcc/contentful/test/double.rb +1 -1
- data/lib/wcc/contentful/test/factory.rb +2 -4
- data/lib/wcc/contentful/version.rb +1 -1
- data/lib/wcc/contentful.rb +17 -6
- 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.
|
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:
|
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.
|
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:
|
513
|
+
version: 1.3.1
|
510
514
|
requirements: []
|
511
|
-
rubygems_version: 3.
|
512
|
-
signing_key:
|
515
|
+
rubygems_version: 3.3.7
|
516
|
+
signing_key:
|
513
517
|
specification_version: 4
|
514
518
|
summary: '[](https://rubygems.org/gems/wcc-contentful)
|
515
519
|
[](https://circleci.com/gh/watermarkchurch/wcc-contentful)
|
@@ -526,7 +530,7 @@ summary: '[](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
|
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: '[](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 #
|
624
|
-
#
|
625
|
-
UTC...> # Find objects
|
626
|
-
# => #<
|
627
|
-
UTC...> # Use operators to filter by a field # must use full notation
|
628
|
-
(except ID)
|
629
|
-
}) # => [#<
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
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: '[](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"=> ...}, ...] ```
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
to
|
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: '[](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
|
708
|
-
|
709
|
-
simply include {WCC::Contentful::Middleware::Store}
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
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: '[](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 #
|
770
|
-
|
771
|
-
|
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
|
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: '[](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}.
|
787
|
-
|
788
|
-
will
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
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
|