diff --git a/jsonapi-rails.gemspec b/jsonapi-rails.gemspec index 65856fe..656a00b 100644 --- a/jsonapi-rails.gemspec +++ b/jsonapi-rails.gemspec @@ -14,7 +14,7 @@ Gem::Specification.new do |spec| spec.files = Dir['README.md', 'lib/**/*'] spec.require_path = 'lib' - spec.add_dependency 'jsonapi-rb', '~> 0.1', '>= 0.1.3' + spec.add_dependency 'jsonapi-rb', '~> 0.2.1' spec.add_development_dependency 'rails', '~> 5.0' spec.add_development_dependency 'sqlite3' diff --git a/lib/jsonapi/rails/railtie.rb b/lib/jsonapi/rails/railtie.rb index 77823b0..2ac26e4 100644 --- a/lib/jsonapi/rails/railtie.rb +++ b/lib/jsonapi/rails/railtie.rb @@ -10,8 +10,8 @@ module Rails class Railtie < ::Rails::Railtie MEDIA_TYPE = 'application/vnd.api+json'.freeze RENDERERS = { - jsonapi: JSONAPI::Rails.rails_renderer(SuccessRenderer), - jsonapi_error: JSONAPI::Rails.rails_renderer(ErrorRenderer) + jsonapi: SuccessRenderer.new, + jsonapi_error: ErrorsRenderer.new }.freeze initializer 'jsonapi-rails.action_controller' do @@ -27,8 +27,20 @@ class Railtie < ::Rails::Railtie ::ActionDispatch::ParamsParser::DEFAULT_PARSERS[Mime[:jsonapi]] = PARSER end - RENDERERS.each do |key, renderer| - ::ActionController::Renderers.add(key, &renderer) + ::ActionController::Renderers.add(:jsonapi) do |resources, options| + self.content_type ||= Mime[:jsonapi] + + RENDERERS[:jsonapi].render(resources, options).to_json + end + + ::ActionController::Renderers.add(:jsonapi_error) do |errors, options| + # Renderer proc is evaluated in the controller context, so it + # has access to the request object. + reverse_mapping = request.env[ActionController::REVERSE_MAPPING_KEY] + options = options.merge(_reverse_mapping: reverse_mapping) + self.content_type ||= Mime[:jsonapi] + + RENDERERS[:jsonapi_error].render(errors, options).to_json end JSONAPI::Deserializable::Resource.configure do |config| diff --git a/lib/jsonapi/rails/renderer.rb b/lib/jsonapi/rails/renderer.rb index 4fd13c2..964d1ac 100644 --- a/lib/jsonapi/rails/renderer.rb +++ b/lib/jsonapi/rails/renderer.rb @@ -3,7 +3,13 @@ module JSONAPI module Rails class SuccessRenderer - def self.render(resources, options) + def initialize(renderer = JSONAPI::Serializable::SuccessRenderer.new) + @renderer = renderer + + freeze + end + + def render(resources, options) opts = options.dup # TODO(beauby): Move this to a global configuration. default_exposures = { @@ -12,29 +18,20 @@ def self.render(resources, options) opts[:expose] = default_exposures.merge!(opts[:expose] || {}) opts[:jsonapi] = opts.delete(:jsonapi_object) - JSONAPI::Serializable::Renderer.render(resources, opts) + @renderer.render(resources, opts) end end - class ErrorRenderer - def self.render(errors, options) - # TODO(beauby): SerializableError inference on AR validation errors. - JSONAPI::Serializable::ErrorRenderer.render(errors, options) - end - end + class ErrorsRenderer + def initialize(renderer = JSONAPI::Serializable::ErrorsRenderer.new) + @renderer = renderer - module_function + freeze + end - # @api private - def rails_renderer(renderer) - proc do |json, options| - # Renderer proc is evaluated in the controller context, so it - # has access to the request object. - reverse_mapping = request.env[ActionController::REVERSE_MAPPING_KEY] - options = options.merge(_reverse_mapping: reverse_mapping) - json = renderer.render(json, options).to_json unless json.is_a?(String) - self.content_type ||= Mime[:jsonapi] - self.response_body = json + def render(errors, options) + # TODO(beauby): SerializableError inference on AR validation errors. + @renderer.render(errors, options) end end end