Skip to content

Commit 4c7a09f

Browse files
committed
remove CBP request attempt in favor of a more descriptive approach about endpoints that do support CBP
1 parent b6bf1fb commit 4c7a09f

File tree

5 files changed

+58
-48
lines changed

5 files changed

+58
-48
lines changed

lib/zendesk_api/client.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,24 +37,24 @@ class Client
3737
def method_missing(method, *args, &block)
3838
method = method.to_s
3939
options = args.last.is_a?(Hash) ? args.pop : {}
40-
4140
unless config.use_resource_cache
42-
raise "Resource for #{method} does not exist" unless method_as_class(method)
43-
return ZendeskAPI::Collection.new(self, method_as_class(method), options)
41+
resource_class = resource_class_for(method)
42+
raise "Resource for #{method} does not exist" unless resource_class
43+
return ZendeskAPI::Collection.new(self, resource_class, options)
4444
end
4545

4646
@resource_cache[method] ||= { :class => nil, :cache => ZendeskAPI::LRUCache.new }
4747
if !options.delete(:reload) && (cached = @resource_cache[method][:cache].read(options.hash))
4848
cached
4949
else
50-
@resource_cache[method][:class] ||= method_as_class(method)
50+
@resource_cache[method][:class] ||= resource_class_for(method)
5151
raise "Resource for #{method} does not exist" unless @resource_cache[method][:class]
5252
@resource_cache[method][:cache].write(options.hash, ZendeskAPI::Collection.new(self, @resource_cache[method][:class], options))
5353
end
5454
end
5555

5656
def respond_to?(method, *args)
57-
((cache = @resource_cache[method]) && cache[:class]) || !method_as_class(method).nil? || super
57+
((cache = @resource_cache[method]) && cache[:class]) || !resource_class_for(method).nil? || super
5858
end
5959

6060
# Returns the current user (aka me)
@@ -184,7 +184,7 @@ def build_connection
184184

185185
private
186186

187-
def method_as_class(method)
187+
def resource_class_for(method)
188188
klass_as_string = ZendeskAPI::Helpers.modulize_string(Inflection.singular(method.to_s.gsub(/\W/, '')))
189189
ZendeskAPI::Association.class_from_namespace(klass_as_string)
190190
end

lib/zendesk_api/collection.rb

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -356,30 +356,27 @@ def intentional_obp_request?
356356
Helpers.present?(@options["page"]) && !cbp_request?
357357
end
358358

359-
def should_try_cbp?(path_query_link)
360-
not_supported_endpoints = %w[show_many]
361-
not_supported_endpoints.none? { |endpoint| path_query_link.end_with?(endpoint) }
359+
def supports_cursor_based_pagination?
360+
@resource_class.const_defined?(:CBP_ACTIONS) && @resource_class.const_get(:CBP_ACTIONS).any? { |supported_path| path.end_with?(supported_path) }
361+
end
362+
363+
def first_of_multiple_pages?
364+
@next_page.nil?
365+
end
366+
367+
def modify_request_for_cbp
368+
@options_per_page_was = @options.delete("per_page")
369+
# Default to CBP by using the page param as a map
370+
@options.page = { size: (@options_per_page_was || DEFAULT_PAGE_SIZE) }
362371
end
363372

364373
def get_resources(path_query_link)
365374
if intentional_obp_request?
366375
warn "Offset Based Pagination will be deprecated soon"
367-
elsif @next_page.nil? && should_try_cbp?(path_query_link)
368-
@options_per_page_was = @options.delete("per_page")
369-
# Default to CBP by using the page param as a map
370-
@options.page = { size: (@options_per_page_was || DEFAULT_PAGE_SIZE) }
371-
end
372-
373-
begin
374-
# Try CBP first, unless the user explicitly asked for OBP
375-
@response = get_response(path_query_link)
376-
rescue ZendeskAPI::Error::NetworkError => e
377-
raise e if intentional_obp_request?
378-
# Fallback to OBP if CBP didn't work, using per_page param
379-
@options.per_page = @options_per_page_was
380-
@options.page = nil
381-
@response = get_response(path_query_link)
376+
elsif supports_cursor_based_pagination? && first_of_multiple_pages?
377+
modify_request_for_cbp
382378
end
379+
@response = get_response(path_query_link)
383380

384381
# Keep pre-existing behaviour for search/export
385382
if path_query_link == "search/export"
@@ -394,7 +391,6 @@ def set_page_and_count(body)
394391
@next_page, @prev_page = page_links(body)
395392

396393
if cbp_response?(body)
397-
# We'll delete the one we don't need in #next or #prev
398394
@options["page"]["after"] = body["meta"]["after_cursor"]
399395
@options["page"]["before"] = body["meta"]["before_cursor"]
400396
elsif @next_page =~ /page=(\d+)/
@@ -541,9 +537,13 @@ def array_method(name, *args, &block)
541537
to_a.public_send(name, *args, &block)
542538
end
543539

540+
# If you call client.tickets.foo - and foo is not an attribute nor an association, it ends up here, as a new collection
544541
def next_collection(name, *args, &block)
545542
opts = args.last.is_a?(Hash) ? args.last : {}
546-
opts.merge!(:collection_path => @collection_path.dup.push(name))
543+
opts.merge!(collection_path: [*@collection_path, name], page: nil)
544+
# why page: nil ?
545+
# when you do client.tickets.fetch followed by client.tickets.foos => the request to /tickets/foos will
546+
# have the options page set to whatever the last options were for the tickets collection
547547
self.class.new(@client, @resource_class, @options.merge(opts))
548548
end
549549

lib/zendesk_api/resources.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,8 @@ class Ticket < Resource
378378
extend UpdateMany
379379
extend DestroyMany
380380

381+
CBP_ACTIONS = %w[tickets].freeze
382+
381383
# Unlike other attributes, "comment" is not a property of the ticket,
382384
# but is used as a "comment on save", so it should be kept unchanged,
383385
# See https://github.com/zendesk/zendesk_api_client_rb/issues/321

spec/core/collection_spec.rb

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,14 @@
2626
let(:response_page1) { double("response_page1", body: response_body_page1) }
2727

2828
before do
29-
allow(subject).to receive(:get_response).with("test_resources").and_return(response_page1)
29+
stub_json_request(:get, %r{test_resources}, json(response_body_page1))
3030
end
3131

3232
context "when CBP is used" do
3333
it "is empty on the first page" do
34-
subject.fetch
35-
36-
expect(subject.prev).to eq([])
34+
stub_const("ZendeskAPI::TestResource::CBP_ACTIONS", %w[test_resources])
35+
collection = ZendeskAPI::Collection.new(client, ZendeskAPI::TestResource)
36+
expect(collection.prev).to eq([])
3737
end
3838
end
3939
end
@@ -1015,8 +1015,9 @@ def to_proc
10151015
end
10161016
end
10171017

1018-
context "when fetching a collection" do
1018+
context "when fetching a collection that supports CBP" do
10191019
before do
1020+
stub_const("ZendeskAPI::TestResource::CBP_ACTIONS", %w[test_resources])
10201021
expect(subject).to receive(:get_response).with("test_resources").and_return(cbp_success_response)
10211022
end
10221023

@@ -1033,18 +1034,6 @@ def to_proc
10331034
end
10341035
end
10351036

1036-
context "when the endpoint does not support CBP" do
1037-
before do
1038-
expect(subject).to receive(:get_response).with("test_resources").and_raise(ZendeskAPI::Error::NetworkError).twice
1039-
end
1040-
1041-
it "tries an OBP request after a failed CBP request" do
1042-
subject.per_page(2).fetch
1043-
expect(subject.instance_variable_get(:@options)["per_page"]).to eq(2)
1044-
expect(subject.instance_variable_get(:@options)["page"]).to be_nil
1045-
end
1046-
end
1047-
10481037
describe "#all going through multiple pages" do
10491038
def generate_response(index, has_more)
10501039
{
@@ -1061,6 +1050,7 @@ def generate_response(index, has_more)
10611050
}
10621051
end
10631052
before do
1053+
stub_const("ZendeskAPI::TestResource::CBP_ACTIONS", %w[test_resources])
10641054
stub_json_request(:get, %r{test_resources\?page%5Bsize%5D=1}, json(generate_response(1, true)))
10651055
stub_json_request(:get, %r{test_resources.json\/\?page%5Bafter%5D=after1&page%5Bsize%5D=1}, json(generate_response(2, true)))
10661056
stub_json_request(:get, %r{test_resources.json\/\?page%5Bafter%5D=after2&page%5Bsize%5D=1}, json(generate_response(3, true)))
@@ -1069,12 +1059,12 @@ def generate_response(index, has_more)
10691059

10701060
it "fetches all pages and yields the correct arguments" do
10711061
expect do |b|
1072-
silence_logger { subject.all(&b) }
1062+
silence_logger { subject.per_page(1).all(&b) }
10731063
end.to yield_successive_args(
1074-
[ZendeskAPI::TestResource.new(client, id: 1), "after" => "after1", "before" => "before0", "size" => 100],
1075-
[ZendeskAPI::TestResource.new(client, id: 2), "after" => "after2", "before" => "before1", "size" => 100],
1076-
[ZendeskAPI::TestResource.new(client, id: 3), "after" => "after3", "before" => "before2", "size" => 100],
1077-
[ZendeskAPI::TestResource.new(client, id: 4), "after" => "after4", "before" => "before3", "size" => 100]
1064+
[ZendeskAPI::TestResource.new(client, id: 1), "after" => "after1", "before" => "before0", "size" => 1],
1065+
[ZendeskAPI::TestResource.new(client, id: 2), "after" => "after2", "before" => "before1", "size" => 1],
1066+
[ZendeskAPI::TestResource.new(client, id: 3), "after" => "after3", "before" => "before2", "size" => 1],
1067+
[ZendeskAPI::TestResource.new(client, id: 4), "after" => "after4", "before" => "before3", "size" => 1]
10781068
)
10791069
end
10801070
end

spec/live/ticket_spec.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,24 @@ def valid_attributes
6262
end
6363
end
6464

65+
describe "#show_many" do
66+
let(:how_many_tickets) { 10 }
67+
before do
68+
VCR.use_cassette("get_tickets_show_many") do
69+
@tickets = client.tickets.per_page(how_many_tickets).fetch
70+
end
71+
72+
VCR.use_cassette("tickets_show_many_with_ids") do
73+
@tickets_from_show_many = client.tickets.show_many(ids: @tickets.map(&:id)).fetch
74+
end
75+
end
76+
77+
it "returns the correct number of tickets" do
78+
expect(@tickets_from_show_many.count).to eq(how_many_tickets)
79+
expect(@tickets.map(&:id).sort).to eq(@tickets_from_show_many.map(&:id).sort)
80+
end
81+
end
82+
6583
describe "#attributes_for_save" do
6684
let :ticket do
6785
described_class.new(instance_double(ZendeskAPI::Client), status: :new)

0 commit comments

Comments
 (0)