wcc-contentful 1.3.2 → 1.4.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +80 -13
- data/lib/wcc/contentful/active_record_shim.rb +2 -2
- 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_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 +78 -46
@@ -0,0 +1,220 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.shared_examples 'supports locales in queries' do |feature_set|
|
4
|
+
describe 'supports query options: { locale: ... }' do
|
5
|
+
before { skip('querying alternate locales not supported') } if feature_set == false
|
6
|
+
|
7
|
+
generator = proc { "test#{rand(1..10_000)}" }
|
8
|
+
|
9
|
+
let(:desired_value) {
|
10
|
+
generator.call
|
11
|
+
}
|
12
|
+
|
13
|
+
let(:data) {
|
14
|
+
1.upto(3).map do |i|
|
15
|
+
{
|
16
|
+
'sys' => { 'id' => "k#{i}", 'contentType' => { 'sys' => { 'id' => 'test1' } } },
|
17
|
+
'fields' => {
|
18
|
+
'slug' => {
|
19
|
+
'en-US' => generator.call,
|
20
|
+
'es-ES' => generator.call
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}
|
24
|
+
end
|
25
|
+
}
|
26
|
+
|
27
|
+
let(:desired) {
|
28
|
+
{
|
29
|
+
'sys' => { 'id' => "k#{rand}", 'contentType' => { 'sys' => { 'id' => 'test1' } } },
|
30
|
+
'fields' => {
|
31
|
+
'slug' => {
|
32
|
+
'en-US' => generator.call,
|
33
|
+
'es-ES' => desired_value
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
context 'when localized value exists' do
|
40
|
+
it 'find_by can apply filter object' do
|
41
|
+
[*data, desired].shuffle.each { |d| subject.set(d.dig('sys', 'id'), d) }
|
42
|
+
|
43
|
+
# act
|
44
|
+
found = subject.find_by(content_type: 'test1',
|
45
|
+
filter: { 'slug' => desired_value },
|
46
|
+
options: { locale: 'es-ES' })
|
47
|
+
|
48
|
+
# assert
|
49
|
+
expect(found).to_not be_nil
|
50
|
+
expect(found).to eq(desired)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'find_by can find value in array' do
|
54
|
+
data =
|
55
|
+
1.upto(3).map do |i|
|
56
|
+
{
|
57
|
+
'sys' => {
|
58
|
+
'id' => "k#{i}",
|
59
|
+
'contentType' => { 'sys' => { 'id' => 'test1' } }
|
60
|
+
},
|
61
|
+
'fields' => {
|
62
|
+
'slug' => {
|
63
|
+
'en-US' => [generator.call, generator.call],
|
64
|
+
'es-ES' => [generator.call, generator.call]
|
65
|
+
}
|
66
|
+
}
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
desired_value = generator.call
|
71
|
+
desired = {
|
72
|
+
'sys' => { 'id' => "k#{rand}", 'contentType' => { 'sys' => { 'id' => 'test1' } } },
|
73
|
+
'fields' => {
|
74
|
+
'slug' => {
|
75
|
+
'en-US' => [generator.call, generator.call],
|
76
|
+
'es-ES' => [generator.call, desired_value]
|
77
|
+
}
|
78
|
+
}
|
79
|
+
}
|
80
|
+
|
81
|
+
data << desired
|
82
|
+
data.shuffle.each { |d| subject.set(d.dig('sys', 'id'), d) }
|
83
|
+
|
84
|
+
# act
|
85
|
+
found = subject.find_by(content_type: 'test1',
|
86
|
+
filter: { 'slug' => { eq: desired_value } },
|
87
|
+
options: { locale: 'es-ES' })
|
88
|
+
|
89
|
+
# assert
|
90
|
+
expect(found).to_not be_nil
|
91
|
+
expect(found).to eq(desired)
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'find_all can apply operator' do
|
95
|
+
desired =
|
96
|
+
4.upto(5).map do |i|
|
97
|
+
{
|
98
|
+
'sys' => { 'id' => "d#{i}", 'contentType' => { 'sys' => { 'id' => 'test1' } } },
|
99
|
+
'fields' => {
|
100
|
+
'slug' => {
|
101
|
+
'en-US' => generator.call,
|
102
|
+
'es-ES' => desired_value
|
103
|
+
}
|
104
|
+
}
|
105
|
+
}
|
106
|
+
end
|
107
|
+
|
108
|
+
[*data, *desired].shuffle.each { |d| subject.set(d.dig('sys', 'id'), d) }
|
109
|
+
|
110
|
+
# act
|
111
|
+
found = subject.find_all(content_type: 'test1', options: { locale: 'es-ES' })
|
112
|
+
.eq('slug', desired_value)
|
113
|
+
|
114
|
+
# assert
|
115
|
+
expect(found.count).to eq(2)
|
116
|
+
sorted = found.to_a.sort_by { |item| item.dig('sys', 'id') }
|
117
|
+
expect(sorted).to eq(desired)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'using fallback locales' do
|
122
|
+
before { pending('querying alternate locales not yet implemented') } if feature_set&.to_s == 'pending'
|
123
|
+
|
124
|
+
before do
|
125
|
+
allow(configuration).to receive(:locale_fallbacks)
|
126
|
+
.and_return({
|
127
|
+
'es-MX' => 'es-ES',
|
128
|
+
'es-ES' => 'en-US'
|
129
|
+
})
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'find_by can apply filter object' do
|
133
|
+
[*data, desired].shuffle.each { |d| subject.set(d.dig('sys', 'id'), d) }
|
134
|
+
|
135
|
+
# act
|
136
|
+
found = subject.find_by(content_type: 'test1',
|
137
|
+
filter: { 'slug' => desired_value },
|
138
|
+
options: { locale: 'es-MX' })
|
139
|
+
|
140
|
+
# assert
|
141
|
+
expect(found).to_not be_nil
|
142
|
+
expect(found).to eq(desired)
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'find_by can find value in array' do
|
146
|
+
data =
|
147
|
+
1.upto(3).map do |i|
|
148
|
+
{
|
149
|
+
'sys' => {
|
150
|
+
'id' => "k#{i}",
|
151
|
+
'contentType' => { 'sys' => { 'id' => 'test1' } }
|
152
|
+
},
|
153
|
+
'fields' => {
|
154
|
+
'slug' => {
|
155
|
+
'en-US' => [generator.call, generator.call],
|
156
|
+
'es-ES' => [generator.call, generator.call]
|
157
|
+
}
|
158
|
+
}
|
159
|
+
}
|
160
|
+
end
|
161
|
+
|
162
|
+
desired_value = generator.call
|
163
|
+
desired = {
|
164
|
+
'sys' => { 'id' => "k#{rand}", 'contentType' => { 'sys' => { 'id' => 'test1' } } },
|
165
|
+
'fields' => {
|
166
|
+
'slug' => {
|
167
|
+
'en-US' => [generator.call, generator.call],
|
168
|
+
'es-ES' => [generator.call, desired_value]
|
169
|
+
}
|
170
|
+
}
|
171
|
+
}
|
172
|
+
|
173
|
+
data << desired
|
174
|
+
data.shuffle.each { |d| subject.set(d.dig('sys', 'id'), d) }
|
175
|
+
|
176
|
+
# act
|
177
|
+
found = subject.find_by(content_type: 'test1',
|
178
|
+
filter: { 'slug' => { eq: desired_value } },
|
179
|
+
options: { locale: 'es-MX' })
|
180
|
+
|
181
|
+
# assert
|
182
|
+
expect(found).to_not be_nil
|
183
|
+
expect(found).to eq(desired)
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'find_all can apply operator' do
|
187
|
+
desired = [
|
188
|
+
{
|
189
|
+
'sys' => { 'id' => 'd1', 'contentType' => { 'sys' => { 'id' => 'test1' } } },
|
190
|
+
'fields' => {
|
191
|
+
'slug' => {
|
192
|
+
'en-US' => generator.call,
|
193
|
+
'es-ES' => desired_value
|
194
|
+
}
|
195
|
+
}
|
196
|
+
},
|
197
|
+
{
|
198
|
+
'sys' => { 'id' => 'd2', 'contentType' => { 'sys' => { 'id' => 'test1' } } },
|
199
|
+
'fields' => {
|
200
|
+
'slug' => {
|
201
|
+
'en-US' => desired_value
|
202
|
+
}
|
203
|
+
}
|
204
|
+
}
|
205
|
+
]
|
206
|
+
|
207
|
+
[*data, *desired].shuffle.each { |d| subject.set(d.dig('sys', 'id'), d) }
|
208
|
+
|
209
|
+
# act
|
210
|
+
found = subject.find_all(content_type: 'test1', options: { locale: 'es-MX' })
|
211
|
+
.eq('slug', desired_value)
|
212
|
+
|
213
|
+
# assert
|
214
|
+
expect(found.count).to eq(2)
|
215
|
+
sorted = found.to_a.sort_by { |item| item.dig('sys', 'id') }
|
216
|
+
expect(sorted).to eq(desired)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
@@ -46,7 +46,7 @@ RSpec.shared_examples 'supports :eq operator' do
|
|
46
46
|
'id' => "k#{i}",
|
47
47
|
'contentType' => { 'sys' => { 'id' => 'test1' } }
|
48
48
|
},
|
49
|
-
'fields' => {
|
49
|
+
'fields' => { type.to_s => { 'en-US' => [generator.call, generator.call] } }
|
50
50
|
}
|
51
51
|
end
|
52
52
|
|
@@ -4,6 +4,7 @@ require_relative './rspec_examples/basic_store'
|
|
4
4
|
require_relative './rspec_examples/operators'
|
5
5
|
require_relative './rspec_examples/nested_queries'
|
6
6
|
require_relative './rspec_examples/include_param'
|
7
|
+
require_relative './rspec_examples/locale_queries'
|
7
8
|
|
8
9
|
# rubocop:disable Style/BlockDelimiters
|
9
10
|
|
@@ -24,6 +25,11 @@ require_relative './rspec_examples/include_param'
|
|
24
25
|
# all linked entries of an object in a single query.
|
25
26
|
# If your store does not respect the include parameter, then the Model layer
|
26
27
|
# will be calling #find a lot in order to resolve linked entries.
|
28
|
+
# [:locale_queries] - This feature defines how the store respects the `locale: x`
|
29
|
+
# key in the Options hash. If this option is set, then the store needs to
|
30
|
+
# compare the query to the appropriate localized value.
|
31
|
+
# If the store does not support this, then either the application should not
|
32
|
+
# use multiple locales OR should always query using the default locale.
|
27
33
|
#
|
28
34
|
# @example
|
29
35
|
# require 'wcc/contentful/store/rspec_examples'
|
@@ -38,13 +44,19 @@ require_relative './rspec_examples/include_param'
|
|
38
44
|
RSpec.shared_examples 'contentful store' do |feature_set|
|
39
45
|
feature_set = {
|
40
46
|
nested_queries: 'pending',
|
41
|
-
include_param: 'pending'
|
47
|
+
include_param: 'pending',
|
48
|
+
locale_queries: 'pending'
|
42
49
|
}.merge(feature_set&.symbolize_keys || {})
|
43
50
|
|
51
|
+
let(:configuration) {
|
52
|
+
WCC::Contentful::Configuration.new
|
53
|
+
}
|
54
|
+
|
44
55
|
include_examples 'basic store'
|
45
56
|
include_examples 'operators', feature_set[:operators]
|
46
57
|
include_examples 'supports nested queries', feature_set[:nested_queries]
|
47
58
|
include_examples 'supports include param', feature_set[:include_param]
|
59
|
+
include_examples 'supports locales in queries', feature_set[:locale_queries]
|
48
60
|
end
|
49
61
|
|
50
62
|
# rubocop:enable Style/BlockDelimiters
|
@@ -138,7 +138,7 @@ module WCC::Contentful
|
|
138
138
|
# This job uses the Contentful Sync API to update the configured store with
|
139
139
|
# the latest data from Contentful.
|
140
140
|
class Job < ActiveJob::Base
|
141
|
-
self.queue_adapter
|
141
|
+
self.queue_adapter ||= :async
|
142
142
|
queue_as :default
|
143
143
|
|
144
144
|
def configuration
|
@@ -24,7 +24,7 @@ module WCC::Contentful::Test::Factory
|
|
24
24
|
|
25
25
|
raw_value = v
|
26
26
|
raw_value = to_raw(v, field.type) if %i[Asset Link].include?(field.type)
|
27
|
-
raw['fields'][field.name]
|
27
|
+
raw['fields'][field.name] = raw_value
|
28
28
|
end
|
29
29
|
|
30
30
|
instance = const.new(raw, context)
|
@@ -84,9 +84,7 @@ module WCC::Contentful::Test::Factory
|
|
84
84
|
end
|
85
85
|
|
86
86
|
def contentful_fields(model)
|
87
|
-
WCC::Contentful::Test::Attributes.defaults(model)
|
88
|
-
{ 'en-US' => v }
|
89
|
-
end
|
87
|
+
WCC::Contentful::Test::Attributes.defaults(model)
|
90
88
|
end
|
91
89
|
|
92
90
|
def to_raw(val, field_type)
|
data/lib/wcc/contentful.rb
CHANGED
@@ -10,6 +10,7 @@ require 'wcc/contentful/configuration'
|
|
10
10
|
require 'wcc/contentful/downloads_schema'
|
11
11
|
require 'wcc/contentful/exceptions'
|
12
12
|
require 'wcc/contentful/helpers'
|
13
|
+
require 'wcc/contentful/entry_locale_transformer'
|
13
14
|
require 'wcc/contentful/link_visitor'
|
14
15
|
require 'wcc/contentful/services'
|
15
16
|
require 'wcc/contentful/simple_client'
|
@@ -40,9 +41,8 @@ module WCC::Contentful
|
|
40
41
|
end
|
41
42
|
|
42
43
|
# Gets all queryable locales.
|
43
|
-
# Reserved for future use.
|
44
44
|
def locales
|
45
|
-
|
45
|
+
configuration&.locale_fallbacks
|
46
46
|
end
|
47
47
|
|
48
48
|
def logger
|
@@ -93,15 +93,18 @@ module WCC::Contentful
|
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
|
-
|
96
|
+
schema =
|
97
97
|
begin
|
98
|
-
JSON.parse(File.read(configuration.schema_file))
|
98
|
+
JSON.parse(File.read(configuration.schema_file)) if File.exist?(configuration.schema_file)
|
99
99
|
rescue JSON::ParserError
|
100
100
|
Services.instance.warn("Schema file invalid, ignoring it: #{configuration.schema_file}")
|
101
101
|
nil
|
102
102
|
end
|
103
103
|
|
104
|
-
|
104
|
+
content_types = schema['contentTypes'] if schema
|
105
|
+
locales = schema['locales'] if schema
|
106
|
+
|
107
|
+
if !schema && %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.
|
@@ -127,7 +130,15 @@ module WCC::Contentful
|
|
127
130
|
services: WCC::Contentful::Services.instance
|
128
131
|
)
|
129
132
|
|
130
|
-
#
|
133
|
+
# Update the locale fallbacks from the schema file, unless they have already
|
134
|
+
# been configured.
|
135
|
+
locales&.each do |locale_hash|
|
136
|
+
next if @configuration.locale_fallbacks[locale_hash['code']]
|
137
|
+
|
138
|
+
@configuration.locale_fallbacks[locale_hash['code']] = locale_hash['fallbackCode']
|
139
|
+
end
|
140
|
+
|
141
|
+
# Enqueue an initial sync
|
131
142
|
WCC::Contentful::SyncEngine::Job.perform_later if defined?(WCC::Contentful::SyncEngine::Job)
|
132
143
|
|
133
144
|
@configuration = @configuration.freeze
|
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
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
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,7 +495,7 @@ 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
500
|
post_install_message:
|
497
501
|
rdoc_options: []
|
@@ -504,9 +508,9 @@ 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
515
|
rubygems_version: 3.3.7
|
512
516
|
signing_key:
|
@@ -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
|
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 #
|
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: '[![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"=> ...}, ...] ```
|
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: '[![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
|
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> ##
|