From 870fd073396dc252f6d810b8171bec499ebf6713 Mon Sep 17 00:00:00 2001 From: Alexandre Friquet Date: Tue, 9 Oct 2018 12:22:32 +0200 Subject: [PATCH 01/12] Returns code on active model validation error. --- lib/jsonapi/rails/serializable_active_model_errors.rb | 8 ++++++-- spec/render_jsonapi_errors_spec.rb | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/jsonapi/rails/serializable_active_model_errors.rb b/lib/jsonapi/rails/serializable_active_model_errors.rb index a97ec71..be058aa 100644 --- a/lib/jsonapi/rails/serializable_active_model_errors.rb +++ b/lib/jsonapi/rails/serializable_active_model_errors.rb @@ -2,6 +2,10 @@ module JSONAPI module Rails # @private class SerializableActiveModelError < Serializable::Error + code do + @code + end + title do "Invalid #{@field}" unless @field.nil? end @@ -26,9 +30,9 @@ def initialize(exposures) def as_jsonapi @errors.keys.flat_map do |key| - @errors.full_messages_for(key).map do |message| + @errors.full_messages_for(key).map.with_index do |message, i| SerializableActiveModelError.new(field: key, message: message, - pointer: @reverse_mapping[key]) + pointer: @reverse_mapping[key], code: @errors.details[key][i][:error]) .as_jsonapi end end diff --git a/spec/render_jsonapi_errors_spec.rb b/spec/render_jsonapi_errors_spec.rb index 035bd2e..463b8ee 100644 --- a/spec/render_jsonapi_errors_spec.rb +++ b/spec/render_jsonapi_errors_spec.rb @@ -17,11 +17,13 @@ { 'errors' => [ { + 'code' => 'blank' 'detail' => 'Name can\'t be blank', 'title' => 'Invalid name', 'source' => { 'pointer' => '/data/attributes/name' } }, { + 'code' => 'invalid' 'detail' => 'Email must be a valid email', 'title' => 'Invalid email', 'source' => { 'pointer' => '/data/attributes/email' } From b15930beb9fd97a49235f816ae5ff394d290ce5d Mon Sep 17 00:00:00 2001 From: Alexandre Friquet Date: Tue, 9 Oct 2018 12:22:32 +0200 Subject: [PATCH 02/12] Returns code on active model validation error. --- lib/jsonapi/rails/serializable_active_model_errors.rb | 8 ++++++-- spec/render_jsonapi_errors_spec.rb | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/jsonapi/rails/serializable_active_model_errors.rb b/lib/jsonapi/rails/serializable_active_model_errors.rb index a97ec71..be058aa 100644 --- a/lib/jsonapi/rails/serializable_active_model_errors.rb +++ b/lib/jsonapi/rails/serializable_active_model_errors.rb @@ -2,6 +2,10 @@ module JSONAPI module Rails # @private class SerializableActiveModelError < Serializable::Error + code do + @code + end + title do "Invalid #{@field}" unless @field.nil? end @@ -26,9 +30,9 @@ def initialize(exposures) def as_jsonapi @errors.keys.flat_map do |key| - @errors.full_messages_for(key).map do |message| + @errors.full_messages_for(key).map.with_index do |message, i| SerializableActiveModelError.new(field: key, message: message, - pointer: @reverse_mapping[key]) + pointer: @reverse_mapping[key], code: @errors.details[key][i][:error]) .as_jsonapi end end diff --git a/spec/render_jsonapi_errors_spec.rb b/spec/render_jsonapi_errors_spec.rb index 035bd2e..463b8ee 100644 --- a/spec/render_jsonapi_errors_spec.rb +++ b/spec/render_jsonapi_errors_spec.rb @@ -17,11 +17,13 @@ { 'errors' => [ { + 'code' => 'blank' 'detail' => 'Name can\'t be blank', 'title' => 'Invalid name', 'source' => { 'pointer' => '/data/attributes/name' } }, { + 'code' => 'invalid' 'detail' => 'Email must be a valid email', 'title' => 'Invalid email', 'source' => { 'pointer' => '/data/attributes/email' } From 8564c90f93d8f6842efe59ff4120faaa92ecbcf7 Mon Sep 17 00:00:00 2001 From: Lucas Date: Fri, 15 Sep 2017 13:34:56 +0200 Subject: [PATCH 03/12] Add content negotiation middleware + fix response content type. --- lib/jsonapi/rails/filter_media_type.rb | 39 +++++++++++++++ lib/jsonapi/rails/railtie.rb | 7 ++- spec/content_negotiation_spec.rb | 17 +++++++ spec/filter_media_type_spec.rb | 69 ++++++++++++++++++++++++++ spec/railtie_spec.rb | 6 +++ 5 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 lib/jsonapi/rails/filter_media_type.rb create mode 100644 spec/content_negotiation_spec.rb create mode 100644 spec/filter_media_type_spec.rb diff --git a/lib/jsonapi/rails/filter_media_type.rb b/lib/jsonapi/rails/filter_media_type.rb new file mode 100644 index 0000000..3977e1d --- /dev/null +++ b/lib/jsonapi/rails/filter_media_type.rb @@ -0,0 +1,39 @@ +require 'rack/media_type' + +module JSONAPI + module Rails + class FilterMediaType + JSONAPI_MEDIA_TYPE = 'application/vnd.api+json'.freeze + + def initialize(app) + @app = app + end + + def call(env) + return [415, {}, []] unless valid_content_type?(env['CONTENT_TYPE']) + return [406, {}, []] unless valid_accept?(env['HTTP_ACCEPT']) + + @app.call(env) + end + + private + + def valid_content_type?(content_type) + Rack::MediaType.type(content_type) != JSONAPI_MEDIA_TYPE || + Rack::MediaType.params(content_type) == {} + end + + def valid_accept?(accept) + return true if accept.nil? + + jsonapi_media_types = + accept.split(',') + .map(&:strip) + .select { |m| Rack::MediaType.type(m) == JSONAPI_MEDIA_TYPE } + + jsonapi_media_types.empty? || + jsonapi_media_types.any? { |m| Rack::MediaType.params(m) == {} } + end + end + end +end diff --git a/lib/jsonapi/rails/railtie.rb b/lib/jsonapi/rails/railtie.rb index 9d083d8..b91b682 100644 --- a/lib/jsonapi/rails/railtie.rb +++ b/lib/jsonapi/rails/railtie.rb @@ -1,5 +1,6 @@ require 'rails/railtie' +require 'jsonapi/rails/filter_media_type' require 'jsonapi/rails/log_subscriber' require 'jsonapi/rails/renderer' @@ -19,7 +20,7 @@ class Railtie < ::Rails::Railtie jsonapi_errors: ErrorsRenderer.new }.freeze - initializer 'jsonapi-rails.init' do + initializer 'jsonapi-rails.init' do |app| register_mime_type register_parameter_parser register_renderers @@ -27,6 +28,8 @@ class Railtie < ::Rails::Railtie require 'jsonapi/rails/controller' include ::JSONAPI::Rails::Controller end + + app.middleware.use FilterMediaType end private @@ -49,7 +52,7 @@ def register_renderers RENDERERS.each do |name, renderer| ::ActionController::Renderers.add(name) do |resources, options| # Renderer proc is evaluated in the controller context. - self.content_type ||= Mime[:jsonapi] + headers['Content-Type'] = Mime[:jsonapi].to_s ActiveSupport::Notifications.instrument('render.jsonapi-rails', resources: resources, diff --git a/spec/content_negotiation_spec.rb b/spec/content_negotiation_spec.rb new file mode 100644 index 0000000..498e851 --- /dev/null +++ b/spec/content_negotiation_spec.rb @@ -0,0 +1,17 @@ +require 'rails_helper' + +describe ActionController::Base, type: :controller do + controller do + def index + render jsonapi: nil + end + end + + context 'when sending data' do + it 'responds with application/vnd.api+json' do + get :index + + expect(response.headers['Content-Type']).to eq('application/vnd.api+json') + end + end +end diff --git a/spec/filter_media_type_spec.rb b/spec/filter_media_type_spec.rb new file mode 100644 index 0000000..e50774a --- /dev/null +++ b/spec/filter_media_type_spec.rb @@ -0,0 +1,69 @@ +require 'rails_helper' + +describe JSONAPI::Rails::FilterMediaType do + let(:app) { ->(_) { [200, {}, ['OK']] } } + + context 'when not receiving JSON API Content-Type' do + it 'passes through' do + env = { 'CONTENT_TYPE' => 'application/json' } + + expect(described_class.new(app).call(env)[0]).to eq(200) + end + end + + context 'when receiving JSON API Content-Type without media parameters' do + it 'passes through' do + env = { 'CONTENT_TYPE' => 'application/vnd.api+json' } + + expect(described_class.new(app).call(env)[0]).to eq(200) + end + end + + context 'when receiving Content-Type with media parameters' do + it 'fails with 415 Unsupported Media Type' do + env = { 'CONTENT_TYPE' => 'application/vnd.api+json; charset=utf-8' } + + expect(described_class.new(app).call(env)[0]).to eq(415) + end + end + + context 'when not receiving JSON API in Accept' do + it 'passes through' do + env = { 'HTTP_ACCEPT' => 'application/json' } + + expect(described_class.new(app).call(env)[0]).to eq(200) + end + end + + context 'when receiving JSON API in Accept without media parameters' do + it 'passes through' do + env = { 'HTTP_ACCEPT' => 'application/vnd.api+json' } + + expect(described_class.new(app).call(env)[0]).to eq(200) + end + end + + context 'when receiving JSON API in Accept without media parameters among others' do + it 'passes through' do + env = { 'HTTP_ACCEPT' => 'application/json, application/vnd.api+json' } + + expect(described_class.new(app).call(env)[0]).to eq(200) + end + end + + context 'when receiving JSON API in Accept with media parameters' do + it 'fails with 406 Not Acceptable' do + env = { 'HTTP_ACCEPT' => 'application/vnd.api+json; charset=utf-8' } + + expect(described_class.new(app).call(env)[0]).to eq(406) + end + end + + context 'when receiving JSON API in Accept with media parameters among others' do + it 'fails with 406 Not Acceptable' do + env = { 'HTTP_ACCEPT' => 'application/json, application/vnd.api+json; charset=utf-8' } + + expect(described_class.new(app).call(env)[0]).to eq(406) + end + end +end diff --git a/spec/railtie_spec.rb b/spec/railtie_spec.rb index 1b1879d..5a98379 100644 --- a/spec/railtie_spec.rb +++ b/spec/railtie_spec.rb @@ -8,4 +8,10 @@ it 'registers the params parser for the JSON API MIME type' do expect(::ActionDispatch::Request.parameter_parsers[:jsonapi]).not_to be_nil end + + it 'registers the FilterMediaType middleware' do + expect( + Rails.application.middleware.include?(JSONAPI::Rails::FilterMediaType) + ).to be true + end end From ebdd763c905f231595a8dbfd95f3602f8062b43a Mon Sep 17 00:00:00 2001 From: Cassidy K Date: Fri, 10 Nov 2017 09:45:59 -0500 Subject: [PATCH 04/12] Adding with_indiferent_access to controller params In Rails 4.2, `to_unsafe_hash` converts the `params` to a Hash and the values can only be accessed with the keys as strings. This change allows for compatibility with Rails 4.2. --- lib/jsonapi/rails/controller/deserialization.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/jsonapi/rails/controller/deserialization.rb b/lib/jsonapi/rails/controller/deserialization.rb index c89934e..1c22b1e 100644 --- a/lib/jsonapi/rails/controller/deserialization.rb +++ b/lib/jsonapi/rails/controller/deserialization.rb @@ -49,7 +49,8 @@ def deserializable_resource(key, options = {}, &block) Class.new(JSONAPI::Rails::DeserializableResource, &block) before_action(options) do |controller| - hash = controller.params.to_unsafe_hash[:_jsonapi] + hash = controller.params.to_unsafe_hash + .with_indifferent_access[:_jsonapi] if hash.nil? JSONAPI::Rails.logger.warn do "Unable to deserialize #{key} because no JSON API payload was" \ From fa852352f265f920c26684807c74661900f84105 Mon Sep 17 00:00:00 2001 From: Alex Semyonov Date: Thu, 25 Oct 2018 01:52:55 +0300 Subject: [PATCH 05/12] Teach generator to respect namespaces --- .../jsonapi/serializable/serializable_generator.rb | 10 +++++++++- .../jsonapi/serializable/templates/serializable.rb.erb | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/generators/jsonapi/serializable/serializable_generator.rb b/lib/generators/jsonapi/serializable/serializable_generator.rb index a77693e..08444ec 100644 --- a/lib/generators/jsonapi/serializable/serializable_generator.rb +++ b/lib/generators/jsonapi/serializable/serializable_generator.rb @@ -8,11 +8,19 @@ class SerializableGenerator < ::Rails::Generators::NamedBase def copy_serializable_file template 'serializable.rb.erb', File.join('app/serializable', class_path, - "serializable_#{file_name}.rb") + "#{serializable_file_name}.rb") end private + def serializable_file_name + "serializable_#{file_name}" + end + + def serializable_class_name + (class_path + [serializable_file_name]).map!(&:camelize).join("::") + end + def model_klass # TODO(beauby): Ensure the model class exists. class_name.safe_constantize diff --git a/lib/generators/jsonapi/serializable/templates/serializable.rb.erb b/lib/generators/jsonapi/serializable/templates/serializable.rb.erb index 45178ca..3af19c1 100644 --- a/lib/generators/jsonapi/serializable/templates/serializable.rb.erb +++ b/lib/generators/jsonapi/serializable/templates/serializable.rb.erb @@ -1,5 +1,5 @@ <% module_namespacing do -%> -class Serializable<%= class_name %> < JSONAPI::Serializable::Resource +class <%= serializable_class_name %> < JSONAPI::Serializable::Resource type '<%= type %>' <% attr_names.each do |attr| -%> attribute :<%= attr %> From 1a9cd6a037a19a531090f6aa7d13135f21cb8ed9 Mon Sep 17 00:00:00 2001 From: Alex Semyonov Date: Thu, 25 Oct 2018 02:25:30 +0300 Subject: [PATCH 06/12] Fix serializable type for namespaced models --- lib/generators/jsonapi/serializable/serializable_generator.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/generators/jsonapi/serializable/serializable_generator.rb b/lib/generators/jsonapi/serializable/serializable_generator.rb index 08444ec..0a19f28 100644 --- a/lib/generators/jsonapi/serializable/serializable_generator.rb +++ b/lib/generators/jsonapi/serializable/serializable_generator.rb @@ -27,7 +27,7 @@ def model_klass end def type - model_klass.name.underscore.pluralize + model_klass.model_name.plural end def attr_names From 72413890024b1cd650cdcc9beb1c8671a0a16d59 Mon Sep 17 00:00:00 2001 From: Dmytro Koval Date: Thu, 7 Mar 2019 20:18:02 +0100 Subject: [PATCH 07/12] Prepare for v0.4.0 release --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 9e11b32..1d0ba9e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.3.1 +0.4.0 From 0fc3f8c2fd8bb5ff14d103c4c3fce10c2c83930c Mon Sep 17 00:00:00 2001 From: Lucas Date: Wed, 6 Sep 2017 09:56:43 +0200 Subject: [PATCH 08/12] Test against multiple rails versions. --- .travis.yml | 17 ++++++++++++----- Gemfile | 13 +++++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index aa9bb36..66d5a3d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,22 +6,29 @@ env: global: - CC_TEST_REPORTER_ID=98c9b3070ea9ac0e8f7afb6570f181506c3a06372b1db5c7deb8e46089fdf132 - GIT_COMMITTED_AT=$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then git log -1 --pretty=format:%ct; else git log -1 --skip 1 --pretty=format:%ct; fi) + matrix: + - "RAILS_VERSION=5.0.7.1" + - "RAILS_VERSION=5.1.6.1" + - "RAILS_VERSION=5.2.2" + - "RAILS_VERSION=master" rvm: - - 2.2.2 - - 2.3.3 + - 2.2.9 + - 2.3.8 + - 2.6.1 - ruby-head matrix: allow_failures: - rvm: ruby-head + - env: "RAILS_VERSION=master" before_script: - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter - chmod +x ./cc-test-reporter - ./cc-test-reporter before-build after_script: - # Preferably you will run test-reporter on branch update events. But - # if you setup travis to build PR updates only, you don't need to run + # Preferably you will run test-reporter on branch update events. But + # if you setup travis to build PR updates only, you don't need to run # the line below - if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT; fi - # In the case where travis is setup to build PR updates only, + # In the case where travis is setup to build PR updates only, # uncomment the line below # - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT diff --git a/Gemfile b/Gemfile index fa75df1..5061ccd 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,16 @@ source 'https://rubygems.org' +rails_version = ENV['RAILS_VERSION'] || "default" +rails = + case rails_version + when 'master' + { github: 'rails/rails' } + when 'default' + '>= 5.0' + else + "~> #{ENV['RAILS_VERSION']}" + end + +gem 'rails', rails + gemspec From a911a10ee3ba7bd68051ad447edd6db02858a6c9 Mon Sep 17 00:00:00 2001 From: Dmytro Koval Date: Sun, 10 Mar 2019 12:37:45 +0100 Subject: [PATCH 09/12] Fix tests --- jsonapi-rails.gemspec | 2 +- spec/dummy/config/initializers/new_framework_defaults.rb | 4 +++- spec/dummy/config/initializers/sqlite3_fix.rb | 3 +++ 3 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 spec/dummy/config/initializers/sqlite3_fix.rb diff --git a/jsonapi-rails.gemspec b/jsonapi-rails.gemspec index d0f8fdb..48387d4 100644 --- a/jsonapi-rails.gemspec +++ b/jsonapi-rails.gemspec @@ -18,7 +18,7 @@ Gem::Specification.new do |spec| spec.add_dependency 'jsonapi-parser', '~> 0.1.0' spec.add_development_dependency 'rails', '~> 5.0' - spec.add_development_dependency 'sqlite3' + spec.add_development_dependency 'sqlite3', '~> 1.3.6' spec.add_development_dependency 'rake', '~> 11.3' spec.add_development_dependency 'rspec-rails', '~> 3.5' spec.add_development_dependency 'with_model', '~> 2.0' diff --git a/spec/dummy/config/initializers/new_framework_defaults.rb b/spec/dummy/config/initializers/new_framework_defaults.rb index 0706caf..69c499f 100644 --- a/spec/dummy/config/initializers/new_framework_defaults.rb +++ b/spec/dummy/config/initializers/new_framework_defaults.rb @@ -18,7 +18,9 @@ Rails.application.config.active_record.belongs_to_required_by_default = true # Do not halt callback chains when a callback returns false. Previous versions had true. -ActiveSupport.halt_callback_chains_on_return_false = false +if Rails.version < '5.2' + ActiveSupport.halt_callback_chains_on_return_false = false +end # Configure SSL options to enable HSTS with subdomains. Previous versions had false. Rails.application.config.ssl_options = { hsts: { subdomains: true } } diff --git a/spec/dummy/config/initializers/sqlite3_fix.rb b/spec/dummy/config/initializers/sqlite3_fix.rb new file mode 100644 index 0000000..53f9423 --- /dev/null +++ b/spec/dummy/config/initializers/sqlite3_fix.rb @@ -0,0 +1,3 @@ +if Rails.version >= '5.1.0' && Rails.application.config.active_record.sqlite3.present? + Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true +end From e06449ec5b09498860b4ff318dc20d52e070b770 Mon Sep 17 00:00:00 2001 From: Lucas Date: Fri, 17 Nov 2017 22:01:34 +0100 Subject: [PATCH 10/12] Fix JSON fragments caching. --- lib/jsonapi/rails/railtie.rb | 2 +- spec/render_jsonapi_spec.rb | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/lib/jsonapi/rails/railtie.rb b/lib/jsonapi/rails/railtie.rb index b91b682..46bab70 100644 --- a/lib/jsonapi/rails/railtie.rb +++ b/lib/jsonapi/rails/railtie.rb @@ -57,7 +57,7 @@ def register_renderers ActiveSupport::Notifications.instrument('render.jsonapi-rails', resources: resources, options: options) do - renderer.render(resources, options, self).to_json + JSON.generate(renderer.render(resources, options, self)) end end end diff --git a/spec/render_jsonapi_spec.rb b/spec/render_jsonapi_spec.rb index 4cf9341..1c3cde1 100644 --- a/spec/render_jsonapi_spec.rb +++ b/spec/render_jsonapi_spec.rb @@ -17,4 +17,38 @@ def index expect(subject.key?('data')).to be true end end + + context 'when using a cache' do + controller do + def serializer + Class.new(JSONAPI::Serializable::Resource) do + type 'users' + attribute :name + + def jsonapi_cache_key(*) + 'foo' + end + end + end + + def index + user = OpenStruct.new(id: 1, name: 'Lucas') + + render jsonapi: user, + class: { OpenStruct: serializer }, + cache: Rails.cache + end + end + + subject { JSON.parse(response.body) } + + it 'renders a JSON API success document' do + get :index + expect(Rails.cache.exist?('foo')).to be true + get :index + + expect(response.content_type).to eq('application/vnd.api+json') + expect(subject.key?('data')).to be true + end + end end From 50ea32c0df77844a688f246c7ac13a33f005a13a Mon Sep 17 00:00:00 2001 From: Pere Joan Martorell Date: Sun, 14 Apr 2019 18:00:39 +0200 Subject: [PATCH 11/12] Make SerializableGenerator to check that given model exists * Raises a Runtime exception if model is not found * Prevents creating the serializer if model not found --- .../serializable/serializable_generator.rb | 9 +++- spec/serializable_generator_spec.rb | 43 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 spec/serializable_generator_spec.rb diff --git a/lib/generators/jsonapi/serializable/serializable_generator.rb b/lib/generators/jsonapi/serializable/serializable_generator.rb index 0a19f28..89605cc 100644 --- a/lib/generators/jsonapi/serializable/serializable_generator.rb +++ b/lib/generators/jsonapi/serializable/serializable_generator.rb @@ -6,6 +6,8 @@ class SerializableGenerator < ::Rails::Generators::NamedBase # TODO(beauby): Implement versioning. def copy_serializable_file + fail "#{class_name} model not found." unless model_exists? + template 'serializable.rb.erb', File.join('app/serializable', class_path, "#{serializable_file_name}.rb") @@ -13,6 +15,12 @@ def copy_serializable_file private + def model_exists? + Rails.application.eager_load! + models = ApplicationRecord.descendants.map(&:name) + !!models.find { |model_name| model_name == class_name } + end + def serializable_file_name "serializable_#{file_name}" end @@ -22,7 +30,6 @@ def serializable_class_name end def model_klass - # TODO(beauby): Ensure the model class exists. class_name.safe_constantize end diff --git a/spec/serializable_generator_spec.rb b/spec/serializable_generator_spec.rb new file mode 100644 index 0000000..29e5ab8 --- /dev/null +++ b/spec/serializable_generator_spec.rb @@ -0,0 +1,43 @@ +require 'rails_helper' +require 'rails/generators' +require_relative File.expand_path("../../lib/generators/jsonapi/serializable/serializable_generator.rb", __FILE__) + +describe Jsonapi::SerializableGenerator do + with_model :User, superclass: ApplicationRecord, scope: :all do + table do |t| + t.string :name + t.string :email + end + end + + before do + @test_case = Rails::Generators::TestCase.new(:fake_test_case) + @test_case.class.tests(described_class) + @test_case.class.destination(File.expand_path("../tmp", File.dirname(__FILE__))) + @test_case.send(:prepare_destination) + end + + context "passing an existent model" do + let(:model_name) { "User" } + + it "creates a serializable resource" do + @test_case.assert_no_file "app/serializable/serializable_user.rb" + @test_case.run_generator([model_name]) + @test_case.assert_file "app/serializable/serializable_user.rb", /SerializableUser/ + end + end + + context "passing an nonexistent model" do + let(:model_name) { "Dummy" } + + it "raises an error" do + expect { @test_case.run_generator([model_name]) }.to raise_error(RuntimeError, "Dummy model not found.") + end + + it "does not create a serializable resource" do + @test_case.assert_no_file "app/serializable/serializable_dummy.rb" do + @test_case.run_generator([model_name]) + end + end + end +end From 08e52832674b34b8c82a487fe623c3429b78944a Mon Sep 17 00:00:00 2001 From: Alexandre Friquet Date: Thu, 10 Dec 2020 14:45:06 +0100 Subject: [PATCH 12/12] Refactor and fix tests. --- lib/jsonapi/rails/serializable_active_model_errors.rb | 9 ++++++--- spec/render_jsonapi_errors_spec.rb | 6 ++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/jsonapi/rails/serializable_active_model_errors.rb b/lib/jsonapi/rails/serializable_active_model_errors.rb index be058aa..480235e 100644 --- a/lib/jsonapi/rails/serializable_active_model_errors.rb +++ b/lib/jsonapi/rails/serializable_active_model_errors.rb @@ -31,9 +31,12 @@ def initialize(exposures) def as_jsonapi @errors.keys.flat_map do |key| @errors.full_messages_for(key).map.with_index do |message, i| - SerializableActiveModelError.new(field: key, message: message, - pointer: @reverse_mapping[key], code: @errors.details[key][i][:error]) - .as_jsonapi + SerializableActiveModelError.new( + field: key, + message: message, + pointer: @reverse_mapping[key], + code: @errors.details[key][i][:error] + ).as_jsonapi end end end diff --git a/spec/render_jsonapi_errors_spec.rb b/spec/render_jsonapi_errors_spec.rb index 463b8ee..20eb68e 100644 --- a/spec/render_jsonapi_errors_spec.rb +++ b/spec/render_jsonapi_errors_spec.rb @@ -17,13 +17,13 @@ { 'errors' => [ { - 'code' => 'blank' + 'code' => 'blank', 'detail' => 'Name can\'t be blank', 'title' => 'Invalid name', 'source' => { 'pointer' => '/data/attributes/name' } }, { - 'code' => 'invalid' + 'code' => 'invalid', 'detail' => 'Email must be a valid email', 'title' => 'Invalid email', 'source' => { 'pointer' => '/data/attributes/email' } @@ -66,11 +66,13 @@ def jsonapi_pointers def create errors = [ { + 'code' => 'blank', detail: 'Name can\'t be blank', title: 'Invalid name', source: { pointer: '/data/attributes/name' } }, { + 'code' => 'invalid', detail: 'Email must be a valid email', title: 'Invalid email', source: { pointer: '/data/attributes/email' }