I was working with the official Ruby gem for the Zendesk API. It’s a quirky little thing but on the whole quite nice to work with. I did run into one little gotcha: in order to retrieve all the items in a paginated collection, you have to use the #all!
or #all
methods (the bang version raises an error), and you must pass it a block.
For example, in order to build a collection of all the suspended tickets, I have to do something like this:
suspended_tickets = []
zendesk.suspended_tickets.all! do |suspended_ticket, _page|
suspended_tickets << suspended_ticket
end
Now I can use the collection as I see fit.
Recalling my earlier adventures with Enumerators in Ruby, I thought I could surely improve upon this solution by monkeypatching and alias-arounding the #all!
method in the zendesk_api gem. Alternatively, I could create a new Enumerator and use it to yield (in the generator sense) values to build the collection. But wait: can’t I ask Ruby to do that for me, without monkeypatching or writing boilerplate code?
suspended_tickets = zendesk.suspended_tickets
.enum_for(:all!)
Nice! Now I can chain method calls to my heart’s content, without the clumsy intermediate array. Here’s what my final solution ended up looking like:
zendesk.suspended_tickets
.enum_for(:all!)
.reject { |suspended_ticket, | INVALID_CAUSES.include?(suspended_ticket.cause) }
.map { |suspended_ticket, | suspended_ticket.id }
.each_slice(BATCH_SIZE) { |ids| zendesk.suspended_tickets.recover_many(verb: :put, ids: ids).fetch }
If you’re ever working with a fussy method that returns a collection but requires a block, I hope this trick comes in handy! Let me know in the comments if you have any questions about or improvements to this pattern.