Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 22 additions & 21 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,35 @@ on:

jobs:
tests:
runs-on: ubuntu-latest
# 22.04: setup-ruby has no Ruby 2.6/2.7 builds for 24.04.
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
ruby:
- 2.6.6
- 2.7.2
rails:
- 6.1.1
- 6.0.3.4
- 5.2.4.4
- 5.1.7
- 5.0.7.2
- 4.2.11
exclude:
- ruby: 2.7.2
rails: 5.0.7.2
- ruby: 2.6.6
rails: 5.0.7.2
- ruby: 2.7.2
rails: 4.2.11
- ruby: 2.6.6
rails: 4.2.11
include:
- { ruby: '2.6', rails: 5.1.7 }
- { ruby: '2.6', rails: 5.2.8.1 }
- { ruby: '2.6', rails: 6.0.6.1 }
- { ruby: '2.6', rails: 6.1.7.10 }
- { ruby: '2.7', rails: 5.2.8.1 }
- { ruby: '2.7', rails: 6.1.7.10 }
- { ruby: '2.7', rails: 7.0.10 }
- { ruby: '3.2', rails: 6.1.7.10 }
- { ruby: '3.2', rails: 7.0.10 }
- { ruby: '3.2', rails: 7.1.6 }
- { ruby: '3.2', rails: 7.2.4 }
- { ruby: '3.2', rails: 8.0.5.2 }
- { ruby: '3.2', rails: 8.1.4.1 }
- { ruby: '3.4', rails: 7.0.10 }
- { ruby: '3.4', rails: 7.1.6 }
- { ruby: '3.4', rails: 7.2.4 }
- { ruby: '3.4', rails: 8.0.5.2 }
- { ruby: '3.4', rails: 8.1.4.1 }
env:
RAILS_VERSION: ${{ matrix.rails }}
name: Ruby ${{ matrix.ruby }} Rails ${{ matrix.rails }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
Expand Down
4 changes: 3 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ version = ENV['RAILS_VERSION'] || 'default'
platforms :ruby do
if version.start_with?('4.2', '5.0')
gem 'sqlite3', '~> 1.3.13'
elsif version == 'default' || version.to_i >= 8
gem 'sqlite3', '>= 2.1'
else
gem 'sqlite3', '~> 1.4'
end
Expand All @@ -21,7 +23,7 @@ when 'master'
gem 'railties', { git: 'https://github.com/rails/rails.git' }
gem 'arel', { git: 'https://github.com/rails/arel.git' }
when 'default'
gem 'railties', '>= 6.0'
gem 'railties', '>= 7.0'
else
gem 'railties', "~> #{version}"
end
5 changes: 4 additions & 1 deletion jsonapi-resources.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ Gem::Specification.new do |spec|

spec.add_development_dependency 'bundler'
spec.add_development_dependency 'rake'
spec.add_development_dependency 'minitest'
# 6 moved minitest/mock out, and Rails before 8.1 doesn't support it.
spec.add_development_dependency 'minitest', '~> 5.0'
spec.add_development_dependency 'minitest-spec-rails'
spec.add_development_dependency 'simplecov'
spec.add_development_dependency 'pry'
Expand All @@ -31,4 +32,6 @@ Gem::Specification.new do |spec|
spec.add_dependency 'activerecord', '>= 4.1'
spec.add_dependency 'railties', '>= 4.1'
spec.add_dependency 'concurrent-ruby'
# A bundled gem, no longer a default one, from Ruby 3.4.
spec.add_dependency 'csv'
end
1 change: 1 addition & 0 deletions lib/jsonapi-resources.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require 'jsonapi/deprecator'
require 'jsonapi/naive_cache'
require 'jsonapi/compiled_json'
require 'jsonapi/resource'
Expand Down
7 changes: 7 additions & 0 deletions lib/jsonapi/deprecator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module JSONAPI
# Rails 7.2 removed the global ActiveSupport::Deprecation.warn; a gem
# warns through its own deprecator, which every supported Rails has.
def self.deprecator
@deprecator ||= ActiveSupport::Deprecation.new('0.10', 'jsonapi-resources')
end
end
4 changes: 2 additions & 2 deletions lib/jsonapi/exceptions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ def errors

def json_api_error(attr_key, message)
create_error_object(code: JSONAPI::VALIDATION_ERROR,
status: :unprocessable_entity,
status: 422, # :unprocessable_content from Rack 3.1, :unprocessable_entity before
title: message,
detail: detail(attr_key, message),
source: { pointer: pointer(attr_key) },
Expand Down Expand Up @@ -507,7 +507,7 @@ def general_error?(attr_key)
class SaveFailed < Error
def errors
[create_error_object(code: JSONAPI::SAVE_FAILED,
status: :unprocessable_entity,
status: 422, # :unprocessable_content from Rack 3.1, :unprocessable_entity before
title: I18n.translate('jsonapi-resources.exceptions.save_failed.title',
default: 'Save failed or was cancelled'),
detail: I18n.translate('jsonapi-resources.exceptions.save_failed.detail',
Expand Down
12 changes: 6 additions & 6 deletions lib/jsonapi/resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ def attribute(attribute_name, options = {})
check_reserved_attribute_name(attr)

if (attr == :id) && (options[:format].nil?)
ActiveSupport::Deprecation.warn('Id without format is no longer supported. Please remove ids from attributes, or specify a format.')
JSONAPI.deprecator.warn('Id without format is no longer supported. Please remove ids from attributes, or specify a format.')
end

check_duplicate_attribute_name(attr) if options[:format].nil?
Expand Down Expand Up @@ -581,11 +581,11 @@ def has_one(*attrs)
end

def belongs_to(*attrs)
ActiveSupport::Deprecation.warn "In #{name} you exposed a `has_one` relationship "\
" using the `belongs_to` class method. We think `has_one`" \
" is more appropriate. If you know what you're doing," \
" and don't want to see this warning again, override the" \
" `belongs_to` class method on your resource."
JSONAPI.deprecator.warn "In #{name} you exposed a `has_one` relationship "\
" using the `belongs_to` class method. We think `has_one`" \
" is more appropriate. If you know what you're doing," \
" and don't want to see this warning again, override the" \
" `belongs_to` class method on your resource."
_add_relationship(Relationship::ToOne, *attrs)
end

Expand Down
14 changes: 7 additions & 7 deletions test/controllers/controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -632,7 +632,7 @@ def test_create_link_to_missing_object
}
}

assert_response :unprocessable_entity
assert_response 422
# TODO: check if this validation is working
assert_match /author - can't be blank/, response.body
assert_nil response.location
Expand Down Expand Up @@ -715,7 +715,7 @@ def test_create_with_invalid_data
}
}

assert_response :unprocessable_entity
assert_response 422

assert_equal "/data/relationships/author", json_response['errors'][0]['source']['pointer']
assert_equal "can't be blank", json_response['errors'][0]['title']
Expand Down Expand Up @@ -1867,7 +1867,7 @@ def test_delete_with_validation_error
delete :destroy, params: { id: post.id }

assert_equal "can't destroy me", json_response['errors'][0]['title']
assert_response :unprocessable_entity
assert_response 422
end

def test_delete_single
Expand Down Expand Up @@ -2444,7 +2444,7 @@ def test_create_validations_missing_attribute
}
}

assert_response :unprocessable_entity
assert_response 422
assert_equal 2, json_response['errors'].size
assert_equal JSONAPI::VALIDATION_ERROR, json_response['errors'][0]['code']
assert_equal JSONAPI::VALIDATION_ERROR, json_response['errors'][1]['code']
Expand All @@ -2466,7 +2466,7 @@ def test_update_validations_missing_attribute
}
}

assert_response :unprocessable_entity
assert_response 422
assert_equal 1, json_response['errors'].size
assert_equal JSONAPI::VALIDATION_ERROR, json_response['errors'][0]['code']
assert_match /name - can't be blank/, response.body
Expand Down Expand Up @@ -3103,7 +3103,7 @@ def test_create_with_invalid_data
}
}

assert_response :unprocessable_entity
assert_response 422

assert_equal "/data/attributes/spouse-name", json_response['errors'][0]['source']['pointer']
assert_equal "can't be blank", json_response['errors'][0]['title']
Expand Down Expand Up @@ -3651,7 +3651,7 @@ def test_save_model_callbacks_fail
}
}

assert_response :unprocessable_entity
assert_response 422
assert_match /Save failed or was cancelled/, json_response['errors'][0]['detail']
end
end
Expand Down
4 changes: 2 additions & 2 deletions test/fixtures/active_record.rb
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,8 @@

create_table :related_things, force: true do |t|
t.string :name
t.references :from, references: :thing
t.references :to, references: :thing
t.references :from
t.references :to

t.timestamps null: false
end
Expand Down
3 changes: 2 additions & 1 deletion test/integration/requests/request_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,8 @@ def test_put_invalid_json

assert_equal 400, status
assert_equal 'Bad Request', json_response['errors'][0]['title']
assert_match 'unexpected token at', json_response['errors'][0]['detail']
# The json gem's message; its wording changed in json 2.10.
assert_match(/unexpected token at|expected ',' or '}' after object value/, json_response['errors'][0]['detail'])
end

def test_put_valid_json_but_array
Expand Down
47 changes: 34 additions & 13 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
end

require 'active_record/railtie'
require 'rails/test_help'
require 'minitest/mock'
require 'jsonapi-resources'
require 'pry'
require 'memory_profiler'
Expand Down Expand Up @@ -53,14 +51,19 @@ class TestApp < Rails::Application
config.action_controller.action_on_unpermitted_parameters = :raise

ActiveRecord::Schema.verbose = false
config.active_record.schema_format = :none
# The tables are created by fixtures/active_record.rb: no schema file to
# dump or keep in sync (:none, which said so, is gone from Rails 8.0).
config.active_record.schema_format = :none if Rails::VERSION::MAJOR < 8
config.active_record.dump_schema_after_migration = false
config.active_record.maintain_test_schema = false if config.active_record.respond_to?(:maintain_test_schema=)
config.active_support.test_order = :random

if Rails::VERSION::MAJOR >= 5
config.active_support.halt_callback_chains_on_return_false = false
config.active_record.time_zone_aware_types = [:time, :datetime]
config.active_record.belongs_to_required_by_default = false
if Rails::VERSION::MINOR >= 2
# Only Rails 5.2 has (and needs) this setting.
if Rails::VERSION::MAJOR == 5 && Rails::VERSION::MINOR == 2
config.active_record.sqlite3.represent_boolean_as_integer = true
end
end
Expand All @@ -78,10 +81,18 @@ class Engine < ::Rails::Engine
end
end

# The app (and its engines) are initialized before rails/test_help, as in a
# generated Rails app: from Rails 7.1 test_help reads Rails.application's
# config while it loads.
TestApp.initialize!

require 'rails/test_help'
require 'minitest/mock'

# Monkeypatch ActionController::TestCase to delete the RAW_POST_DATA on subsequent calls in the same test.
if Rails::VERSION::MAJOR >= 5
module ClearRawPostHeader
def process(action, *args)
def process(action, **args)
@request.delete_header 'RAW_POST_DATA'
super
end
Expand Down Expand Up @@ -209,8 +220,6 @@ def show_queries
end
end

TestApp.initialize!

require File.expand_path('../fixtures/active_record', __FILE__)

module Pets
Expand Down Expand Up @@ -444,6 +453,18 @@ class CatResource < JSONAPI::Resource
# Ensure backward compatibility with Minitest 4
Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test)

# fixture_path= became fixture_paths= in Rails 7.1 and is gone from 7.2.
module FixturesIn
def fixtures_in(path)
if respond_to?(:fixture_paths=)
self.fixture_paths = [path]
else
self.fixture_path = path
end
end
end
Minitest::Test.extend(FixturesIn)

class Minitest::Test
include Helpers::Assertions
include Helpers::ValueMatchers
Expand All @@ -455,20 +476,20 @@ def run_in_transaction?
true
end

self.fixture_path = "#{Rails.root}/fixtures"
fixtures_in "#{Rails.root}/fixtures"
fixtures :all
end

class ActiveSupport::TestCase
self.fixture_path = "#{Rails.root}/fixtures"
fixtures_in "#{Rails.root}/fixtures"
fixtures :all
setup do
@routes = TestApp.routes
end
end

class ActionDispatch::IntegrationTest
self.fixture_path = "#{Rails.root}/fixtures"
fixtures_in "#{Rails.root}/fixtures"
fixtures :all

def assert_jsonapi_response(expected_status, msg = nil)
Expand Down Expand Up @@ -520,13 +541,13 @@ def assert_cacheable_jsonapi_get(url, cached_classes = :all)
end

class ActionController::TestCase
def assert_cacheable_get(action, *args)
def assert_cacheable_get(action, **args)
assert_nil JSONAPI.configuration.resource_cache

normal_queries = []
normal_query_callback = lambda {|_, _, _, _, payload| normal_queries.push payload[:sql] }
ActiveSupport::Notifications.subscribed(normal_query_callback, 'sql.active_record') do
get action, *args
get action, **args
end
non_caching_response = json_response_sans_backtraces
non_caching_status = response.status
Expand Down Expand Up @@ -560,7 +581,7 @@ def assert_cacheable_get(action, *args)
@controller = nil
setup_controller_request_and_response
@request.headers.merge!(orig_request_headers.dup)
get action, *args
get action, **args
end
end
rescue Exception
Expand Down
Loading