Skip to content

Commit f3035e0

Browse files
authored
Merge pull request #4706 from pulibrary/add-sidekiq-compatible-submission-hash
Add Requests::Submission#to_h method that is sidekiq-compatible
2 parents 32b4af2 + 7f097ab commit f3035e0

File tree

3 files changed

+112
-5
lines changed

3 files changed

+112
-5
lines changed

app/models/requests/submission.rb

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def service_errors
8484
end
8585

8686
def pick_up_location
87-
Requests::BibdataService.delivery_locations[items.first["pick_up"]]["library"]
87+
Requests::BibdataService.delivery_locations.dig(items.first&.dig('pick_up'), "library") || {}
8888
end
8989

9090
def marquand?
@@ -96,6 +96,25 @@ def edd?(item)
9696
delivery_mode.present? && delivery_mode == "edd"
9797
end
9898

99+
# Convert the submission to a hash that is compatible that
100+
# Sidekiq can safely serialize to JSON for redis. This means:
101+
# * No application-specific objects (unless they are activerecord db objects)
102+
# * No ActiveSupport::HashWithIndifferentAccess objects, we can only have Hash objects
103+
# * The keys of the hash must all be strings, not symbols
104+
# See https://github.com/sidekiq/sidekiq/wiki/Best-Practices#1-make-your-job-parameters-small-and-simple
105+
def to_h
106+
{
107+
bib: bib.to_hash.stringify_keys,
108+
email: email,
109+
errors: errors.messages.stringify_keys,
110+
items: items.map { |hash| hash.to_hash.stringify_keys },
111+
patron: patron.to_h.to_hash.stringify_keys,
112+
pick_up_location: pick_up_location.to_hash.stringify_keys,
113+
user_barcode:,
114+
user_name:
115+
}.stringify_keys
116+
end
117+
99118
private
100119

101120
def service_by_type(type)

spec/models/requests/submission_spec.rb

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@
3737
"edd_author" => "",
3838
"edd_art_title" => "",
3939
"edd_note" => "",
40-
"pick_up" => "Firestone Library"
41-
},
40+
"pick_up" => "PF"
41+
}.with_indifferent_access,
4242
{
4343
"selected" => "false"
44-
}
44+
}.with_indifferent_access
4545
]
4646
end
4747
let(:bib) do
@@ -50,7 +50,7 @@
5050
"title" => "County and city data book.",
5151
"author" => "United States",
5252
"date" => "1949"
53-
}
53+
}.with_indifferent_access
5454
end
5555
let(:params) do
5656
{
@@ -105,6 +105,39 @@
105105
expect(submission.partner_item?(submission.items.first)).to be false
106106
end
107107
end
108+
109+
describe '#to_h' do
110+
before { stub_delivery_locations }
111+
it 'is compatible with sidekiq' do
112+
expect({ 'args' => submission.to_h }).to be_compatible_with_sidekiq
113+
end
114+
it 'contains a bib' do
115+
expect(submission.to_h['bib']['id']).to eq '994916543506421'
116+
expect(submission.to_h['bib']['title']).to eq 'County and city data book.'
117+
end
118+
it 'contains items' do
119+
expect(submission.to_h['items'].first['call_number']).to eq 'HA202 .U581'
120+
end
121+
it 'contains an email' do
122+
expect(submission.to_h['email']).to eq 'foo@princeton.edu'
123+
end
124+
it 'contains errors' do
125+
expect(submission.to_h['errors']).to be_empty
126+
end
127+
it 'contains a patron' do
128+
expect(submission.to_h['patron']['first_name']).to eq 'Foo'
129+
expect(submission.to_h['patron']['last_name']).to eq 'Request'
130+
end
131+
it 'contains a pick_up_location' do
132+
expect(submission.to_h['pick_up_location']['label']).to eq 'Firestone Library'
133+
end
134+
it 'contains a user_barcode' do
135+
expect(submission.to_h['user_barcode']).to eq '22101007797777'
136+
end
137+
it 'contains a user_name' do
138+
expect(submission.to_h['user_name']).to eq 'foo'
139+
end
140+
end
108141
end
109142

110143
context 'An invalid Submission' do
@@ -132,6 +165,12 @@
132165
expect(invalid_submission.errors.full_messages.size).to be > 0
133166
end
134167
end
168+
describe '#to_h' do
169+
before { stub_delivery_locations }
170+
it 'is compatible with sidekiq' do
171+
expect({ 'args' => invalid_submission.to_h }).to be_compatible_with_sidekiq
172+
end
173+
end
135174
end
136175

137176
context 'Recap' do
@@ -247,6 +286,16 @@
247286
it 'contains an error message' do
248287
expect(submission.errors.messages).to be_truthy
249288
end
289+
290+
describe '#to_h' do
291+
before { stub_delivery_locations }
292+
it 'is compatible with sidekiq' do
293+
expect(submission.to_h).to be_compatible_with_sidekiq
294+
end
295+
it 'contains errors' do
296+
expect(submission.to_h['errors']).to eq({ "items" => [{ "empty_set" => { "text" => "Please Select an Item to Request!", "type" => "options" } }] })
297+
end
298+
end
250299
end
251300

252301
describe 'A submission without a pick-up location' do

spec/support/sidekiq_data_check.rb

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# frozen_string_literal: true
2+
# This class is responsible for checking whether a provided data structure
3+
# is compatible with sidekiq.
4+
#
5+
# See https://github.com/sidekiq/sidekiq/wiki/Best-Practices#1-make-your-job-parameters-small-and-simple
6+
class SidekiqDataCheck
7+
include Sidekiq::JobUtil
8+
def initialize(data_to_check)
9+
@data_to_check = { "args" => data_to_check }
10+
end
11+
12+
def valid?
13+
check
14+
true
15+
rescue ArgumentError
16+
false
17+
end
18+
19+
def error_message
20+
check
21+
rescue ArgumentError => e
22+
e.message
23+
end
24+
25+
private
26+
27+
attr_reader :data_to_check
28+
29+
# Returns nil if valid, raises ArgumentError if not
30+
def check
31+
Sidekiq::Config::DEFAULTS[:on_complex_arguments] = :raise
32+
verify_json data_to_check
33+
end
34+
end
35+
36+
RSpec::Matchers.define :be_compatible_with_sidekiq do
37+
match { |actual| SidekiqDataCheck.new(actual).valid? }
38+
failure_message { |actual| SidekiqDataCheck.new(actual).error_message }
39+
end

0 commit comments

Comments
 (0)