diff --git a/lib/jsonapi_compliable.rb b/lib/jsonapi_compliable.rb index 3ac9c04..e9dbe80 100644 --- a/lib/jsonapi_compliable.rb +++ b/lib/jsonapi_compliable.rb @@ -42,4 +42,25 @@ def self.included(klass) include Base end end + + # @api private + def self.context + Thread.current[:context] ||= {} + end + + # @api private + def self.context=(val) + Thread.current[:context] = val + end + + # @api private + def self.with_context(obj, namespace) + begin + prior = self.context + self.context = { object: obj, namespace: namespace } + yield + ensure + self.context = prior + end + end end diff --git a/lib/jsonapi_compliable/base.rb b/lib/jsonapi_compliable/base.rb index 76dea9b..eb0080f 100644 --- a/lib/jsonapi_compliable/base.rb +++ b/lib/jsonapi_compliable/base.rb @@ -88,10 +88,8 @@ def query_hash # @api private # @yieldreturn Code to run within the current context def wrap_context - if self.class._jsonapi_compliable - jsonapi_resource.with_context(self, action_name.to_sym) do - yield - end + jsonapi_resource.with_context(self, action_name.to_sym) do + yield end end diff --git a/lib/jsonapi_compliable/resource.rb b/lib/jsonapi_compliable/resource.rb index e610d00..1f60c13 100644 --- a/lib/jsonapi_compliable/resource.rb +++ b/lib/jsonapi_compliable/resource.rb @@ -446,12 +446,8 @@ def self.config # @param object The context (Rails controller or equivalent) # @param namespace One of index/show/etc def with_context(object, namespace = nil) - begin - prior = context - @context = { object: object, namespace: namespace } + JsonapiCompliable.with_context(object, namespace) do yield - ensure - @context = prior end end @@ -462,7 +458,11 @@ def with_context(object, namespace = nil) # @see #with_context # @return [Hash] the context hash def context - @context || {} + JsonapiCompliable.context[:object] + end + + def context_namespace + JsonapiCompliable.context[:namespace] end # Build a scope using this Resource configuration @@ -592,7 +592,7 @@ def association_names def allowed_sideloads(namespace = nil) return {} unless sideloading - namespace ||= context[:namespace] + namespace ||= context_namespace sideloads = sideloading.to_hash[:base] if !sideload_whitelist.empty? && namespace sideloads = Util::IncludeParams.scrub(sideloads, sideload_whitelist[namespace]) diff --git a/lib/jsonapi_compliable/scoping/filterable.rb b/lib/jsonapi_compliable/scoping/filterable.rb index 5558a21..d15be17 100644 --- a/lib/jsonapi_compliable/scoping/filterable.rb +++ b/lib/jsonapi_compliable/scoping/filterable.rb @@ -14,7 +14,7 @@ def find_filter!(name) resource.filters.find { |_name, opts| opts[:aliases].include?(name.to_sym) } raise JsonapiCompliable::Errors::BadFilter unless filter_name if guard = filter_value[:if] - raise JsonapiCompliable::Errors::BadFilter if resource.context[:object].send(guard) == false + raise JsonapiCompliable::Errors::BadFilter if resource.context.send(guard) == false end { filter_name => filter_value } end diff --git a/spec/jsonapi_compliable_spec.rb b/spec/jsonapi_compliable_spec.rb index 41bcb1a..957b7d8 100644 --- a/spec/jsonapi_compliable_spec.rb +++ b/spec/jsonapi_compliable_spec.rb @@ -78,24 +78,8 @@ def config(obj) it 'wraps in the resource context' do instance.wrap_context do - expect(instance.jsonapi_resource.context).to eq({ - object: instance, - namespace: :index - }) - end - end - - context 'when the class does not have a resource' do - let(:klass) do - Class.new do - include JsonapiCompliable - end - end - - it 'does nothing' do - instance.wrap_context do - expect(instance.resource).to be_nil - end + expect(instance.jsonapi_resource.context).to eq(instance) + expect(instance.jsonapi_resource.context_namespace).to eq(:index) end end end diff --git a/spec/resource_spec.rb b/spec/resource_spec.rb index ff38ff8..7f0b33f 100644 --- a/spec/resource_spec.rb +++ b/spec/resource_spec.rb @@ -46,19 +46,28 @@ it 'sets/resets correct context' do dbl = double instance.with_context(dbl, :index) do - expect(instance.context).to eq(object: dbl, namespace: :index) + expect(instance.context).to eq(dbl) + expect(instance.context_namespace).to eq(:index) end - expect(instance.context).to eq({}) + expect(instance.context).to be_nil + expect(instance.context_namespace).to be_nil end context 'when an error' do + around do |e| + JsonapiCompliable.with_context('orig', 'orig namespace') do + e.run + end + end + it 'resets the context' do expect { instance.with_context({}, :index) do raise 'foo' end }.to raise_error('foo') - expect(instance.context).to eq({}) + expect(instance.context).to eq('orig') + expect(instance.context_namespace).to eq('orig namespace') end end end diff --git a/spec/support/scope_helper.rb b/spec/support/scope_helper.rb index 2993252..a85c6b6 100644 --- a/spec/support/scope_helper.rb +++ b/spec/support/scope_helper.rb @@ -14,7 +14,7 @@ let(:scope) { resource.build_scope(scope_object, query) } def render(object, opts = {}) - opts[:expose] = { context: resource.context[:object] } + opts[:expose] = { context: resource.context } opts = JsonapiCompliable::Util::RenderOptions.generate(object, query.to_hash[:authors], opts) resolved = opts.delete(:jsonapi) raw_json = JSONAPI::Serializable::Renderer.render(resolved, opts)