Skip to content

Commit 7a7b80e

Browse files
authored
Merge pull request #9 from speee/rails-8.1-support-core
Add Rails 7.1-8.1 support with Ruby 3.3-3.4 compatibility
2 parents e92afc6 + dbb5e1a commit 7a7b80e

16 files changed

Lines changed: 289 additions & 66 deletions

File tree

.github/workflows/ruby.yml

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,36 +31,94 @@ jobs:
3131
- '3.0'
3232
- 3.1
3333
- 3.2
34+
- 3.3
35+
- 3.4
3436
rails:
35-
- 7.0.4
36-
- 6.1.7
37+
- 8.1.2
38+
- 8.0.4
39+
- 7.2.3
40+
- 7.1.6
41+
- 7.0.10
42+
- 6.1.7.10
3743
- 6.0.6
3844
- 5.2.8.1
3945
- 5.1.7
4046
database_url:
4147
- postgresql://postgres:password@localhost:5432/test
4248
- sqlite3:test_db
4349
exclude:
50+
# Ruby 3.4 exclusions (Rails 7.2+)
51+
- ruby: 3.4
52+
rails: 7.1.6
53+
- ruby: 3.4
54+
rails: 7.0.10
55+
- ruby: 3.4
56+
rails: 6.1.7.10
57+
- ruby: 3.4
58+
rails: 6.0.6
59+
- ruby: 3.4
60+
rails: 5.2.8.1
61+
- ruby: 3.4
62+
rails: 5.1.7
63+
# Ruby 3.3 exclusions (Rails 6.1+)
64+
- ruby: 3.3
65+
rails: 6.0.6
66+
- ruby: 3.3
67+
rails: 5.2.8.1
68+
- ruby: 3.3
69+
rails: 5.1.7
70+
# Ruby 3.2 exclusions (Rails 7.0+)
4471
- ruby: 3.2
4572
rails: 6.0.6
4673
- ruby: 3.2
4774
rails: 5.2.8.1
4875
- ruby: 3.2
4976
rails: 5.1.7
77+
# Ruby 3.1 exclusions (Rails 6.1+)
78+
- ruby: 3.1
79+
rails: 8.1.2
80+
- ruby: 3.1
81+
rails: 8.0.4
5082
- ruby: 3.1
5183
rails: 6.0.6
5284
- ruby: 3.1
5385
rails: 5.2.8.1
5486
- ruby: 3.1
5587
rails: 5.1.7
88+
# Ruby 3.0 exclusions (Rails 6.1+)
89+
- ruby: '3.0'
90+
rails: 8.1.2
91+
- ruby: '3.0'
92+
rails: 8.0.4
93+
- ruby: '3.0'
94+
rails: 7.2.3
5695
- ruby: '3.0'
5796
rails: 6.0.6
5897
- ruby: '3.0'
5998
rails: 5.2.8.1
6099
- ruby: '3.0'
61100
rails: 5.1.7
101+
# Ruby 2.7 exclusions (Rails 5.1-7.0)
102+
- ruby: 2.7
103+
rails: 8.1.2
104+
- ruby: 2.7
105+
rails: 8.0.4
106+
- ruby: 2.7
107+
rails: 7.2.3
108+
- ruby: 2.7
109+
rails: 7.1.6
110+
# Ruby 2.6 exclusions (Rails 5.1-6.1)
111+
- ruby: 2.6
112+
rails: 8.1.2
113+
- ruby: 2.6
114+
rails: 8.0.4
115+
- ruby: 2.6
116+
rails: 7.2.3
117+
- ruby: 2.6
118+
rails: 7.1.6
62119
- ruby: 2.6
63-
rails: 7.0.4
120+
rails: 7.0.10
121+
# PostgreSQL not supported on Rails 5.1.7
64122
- database_url: postgresql://postgres:password@localhost:5432/test
65123
rails: 5.1.7
66124
env:

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ test/version_tmp
1919
tmp
2020
coverage
2121
test/log
22+
log/*.log
2223
test_db
2324
test_db-journal
2425
.idea

Gemfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ platforms :ruby do
1313

1414
if version.start_with?('4.2', '5.0')
1515
gem 'sqlite3', '~> 1.3.13'
16+
elsif version.start_with?('8.')
17+
# Rails 8.0+ requires sqlite3 >= 2.1
18+
gem 'sqlite3', '>= 2.1'
1619
else
1720
gem 'sqlite3', '~> 1.4'
1821
end

jsonapi-resources.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,5 @@ Gem::Specification.new do |spec|
3030
spec.add_dependency 'activerecord', '>= 5.1'
3131
spec.add_dependency 'railties', '>= 5.1'
3232
spec.add_dependency 'concurrent-ruby'
33+
spec.add_dependency 'csv' # Required for Ruby 3.4+ (no longer a default gem)
3334
end

lib/jsonapi/acts_as_resource_controller.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,16 @@ def index_related_resources
6363

6464
def get_related_resource
6565
# :nocov:
66-
ActiveSupport::Deprecation.warn "In #{self.class.name} you exposed a `get_related_resource`"\
67-
" action. Please use `show_related_resource` instead."
66+
JSONAPI.warn_deprecated "In #{self.class.name} you exposed a `get_related_resource`"\
67+
" action. Please use `show_related_resource` instead."
6868
show_related_resource
6969
# :nocov:
7070
end
7171

7272
def get_related_resources
7373
# :nocov:
74-
ActiveSupport::Deprecation.warn "In #{self.class.name} you exposed a `get_related_resources`"\
75-
" action. Please use `index_related_resources` instead."
74+
JSONAPI.warn_deprecated "In #{self.class.name} you exposed a `get_related_resources`"\
75+
" action. Please use `index_related_resources` instead."
7676
index_related_resources
7777
# :nocov:
7878
end

lib/jsonapi/basic_resource.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,7 @@ def attribute(attribute_name, options = {})
547547
check_reserved_attribute_name(attr)
548548

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

553553
check_duplicate_attribute_name(attr) if options[:format].nil?
@@ -609,11 +609,11 @@ def has_one(*attrs)
609609
end
610610

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

lib/jsonapi/configuration.rb

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ def exception_class_allowed?(e)
227227
end
228228

229229
def default_processor_klass=(default_processor_klass)
230-
ActiveSupport::Deprecation.warn('`default_processor_klass` has been replaced by `default_processor_klass_name`.')
230+
JSONAPI.warn_deprecated('`default_processor_klass` has been replaced by `default_processor_klass_name`.')
231231
@default_processor_klass = default_processor_klass
232232
end
233233

@@ -241,18 +241,18 @@ def default_processor_klass_name=(default_processor_klass_name)
241241
end
242242

243243
def allow_include=(allow_include)
244-
ActiveSupport::Deprecation.warn('`allow_include` has been replaced by `default_allow_include_to_one` and `default_allow_include_to_many` options.')
244+
JSONAPI.warn_deprecated('`allow_include` has been replaced by `default_allow_include_to_one` and `default_allow_include_to_many` options.')
245245
@default_allow_include_to_one = allow_include
246246
@default_allow_include_to_many = allow_include
247247
end
248248

249249
def whitelist_all_exceptions=(allow_all_exceptions)
250-
ActiveSupport::Deprecation.warn('`whitelist_all_exceptions` has been replaced by `allow_all_exceptions`')
250+
JSONAPI.warn_deprecated('`whitelist_all_exceptions` has been replaced by `allow_all_exceptions`')
251251
@allow_all_exceptions = allow_all_exceptions
252252
end
253253

254254
def exception_class_whitelist=(exception_class_allowlist)
255-
ActiveSupport::Deprecation.warn('`exception_class_whitelist` has been replaced by `exception_class_allowlist`')
255+
JSONAPI.warn_deprecated('`exception_class_whitelist` has been replaced by `exception_class_allowlist`')
256256
@exception_class_allowlist = exception_class_allowlist
257257
end
258258

@@ -314,12 +314,28 @@ def exception_class_whitelist=(exception_class_allowlist)
314314
end
315315

316316
class << self
317-
attr_accessor :configuration
318-
end
317+
attr_writer :configuration
319318

320-
@configuration ||= Configuration.new
319+
def configuration
320+
@configuration ||= Configuration.new
321+
end
322+
end
321323

322324
def self.configure
323-
yield(@configuration)
325+
yield(configuration)
326+
end
327+
328+
# Rails 7.2+ made ActiveSupport::Deprecation.warn a private method
329+
# This helper provides backward-compatible deprecation warnings
330+
def self.warn_deprecated(message)
331+
if defined?(ActiveSupport::Deprecation) && ActiveSupport::Deprecation.respond_to?(:warn)
332+
# Rails < 7.2
333+
ActiveSupport::Deprecation.warn(message)
334+
else
335+
# Rails 7.2+ or fallback - use standard warning with deprecation formatting
336+
# Rails 7.2 doesn't provide a public API for custom deprecation warnings
337+
# So we use Kernel#warn with a deprecation prefix
338+
warn "[DEPRECATION] #{message}"
339+
end
324340
end
325341
end

lib/jsonapi/error.rb

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,26 @@ module JSONAPI
44
class Error
55
attr_accessor :title, :detail, :id, :href, :code, :source, :links, :status, :meta
66

7+
# Rack 3.0+ deprecated :unprocessable_entity in favor of :unprocessable_content
8+
# This mapping ensures compatibility across Rack versions
9+
DEPRECATED_STATUS_SYMBOLS = {
10+
unprocessable_entity: :unprocessable_content
11+
}.freeze
12+
13+
def self.status_code_for(status_symbol)
14+
return nil if status_symbol.nil?
15+
16+
# Try the symbol directly first
17+
code = Rack::Utils::SYMBOL_TO_STATUS_CODE[status_symbol]
18+
19+
# If not found and it's a deprecated symbol, try the new symbol
20+
if code.nil? && DEPRECATED_STATUS_SYMBOLS.key?(status_symbol)
21+
code = Rack::Utils::SYMBOL_TO_STATUS_CODE[DEPRECATED_STATUS_SYMBOLS[status_symbol]]
22+
end
23+
24+
code&.to_s
25+
end
26+
727
def initialize(options = {})
828
@title = options[:title]
929
@detail = options[:detail]
@@ -17,7 +37,7 @@ def initialize(options = {})
1737
@source = options[:source]
1838
@links = options[:links]
1939

20-
@status = Rack::Utils::SYMBOL_TO_STATUS_CODE[options[:status]].to_s
40+
@status = self.class.status_code_for(options[:status])
2141
@meta = options[:meta]
2242
end
2343

@@ -48,7 +68,7 @@ def update_with_overrides(error_object_overrides)
4868

4969
if error_object_overrides[:status]
5070
# :nocov:
51-
@status = Rack::Utils::SYMBOL_TO_STATUS_CODE[error_object_overrides[:status]].to_s
71+
@status = self.class.status_code_for(error_object_overrides[:status])
5272
# :nocov:
5373
end
5474
@meta = error_object_overrides[:meta] || @meta

lib/jsonapi/relationship.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def initialize(name, options = {})
2121
@polymorphic = options.fetch(:polymorphic, false) == true
2222
@polymorphic_types = options[:polymorphic_types]
2323
if options[:polymorphic_relations]
24-
ActiveSupport::Deprecation.warn('Use polymorphic_types instead of polymorphic_relations')
24+
JSONAPI.warn_deprecated('Use polymorphic_types instead of polymorphic_relations')
2525
@polymorphic_types ||= options[:polymorphic_relations]
2626
end
2727

lib/jsonapi/routing_ext.rb

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,30 @@ def jsonapi_resource(*resources, &_block)
4848

4949
resource @resource_type, options do
5050
# :nocov:
51-
if @scope.respond_to? :[]=
51+
if @scope.respond_to?(:[]=)
5252
# Rails 4
5353
@scope[:jsonapi_resource] = @resource_type
5454

55+
if block_given?
56+
yield
57+
else
58+
jsonapi_relationships
59+
end
60+
elsif Rails::VERSION::MAJOR >= 8 && Rails::VERSION::MINOR >= 1
61+
# Rails 8.1+
62+
# Rails 8.1 changed Scope to not support []= and Resource.new signature
63+
# Use instance variable to track resource type
64+
@jsonapi_resource_type = @resource_type
5565
if block_given?
5666
yield
5767
else
5868
jsonapi_relationships
5969
end
6070
else
61-
# Rails 5
62-
jsonapi_resource_scope(SingletonResource.new(@resource_type, api_only?, @scope[:shallow], options), @resource_type) do
71+
# Rails 5-8.0
72+
resource_arg = SingletonResource.new(@resource_type, api_only?, @scope[:shallow], options)
73+
74+
jsonapi_resource_scope(resource_arg, @resource_type) do
6375
if block_given?
6476
yield
6577
else
@@ -123,17 +135,29 @@ def jsonapi_resources(*resources, &_block)
123135

124136
resources @resource_type, options do
125137
# :nocov:
126-
if @scope.respond_to? :[]=
138+
if @scope.respond_to?(:[]=)
127139
# Rails 4
128140
@scope[:jsonapi_resource] = @resource_type
129141
if block_given?
130142
yield
131143
else
132144
jsonapi_relationships
133145
end
146+
elsif Rails::VERSION::MAJOR >= 8 && Rails::VERSION::MINOR >= 1
147+
# Rails 8.1+
148+
# Rails 8.1 changed Scope to not support []= and Resource.new signature
149+
# Use instance variable to track resource type
150+
@jsonapi_resource_type = @resource_type
151+
if block_given?
152+
yield
153+
else
154+
jsonapi_relationships
155+
end
134156
else
135-
# Rails 5
136-
jsonapi_resource_scope(Resource.new(@resource_type, api_only?, @scope[:shallow], options), @resource_type) do
157+
# Rails 5-8.0
158+
resource_arg = Resource.new(@resource_type, api_only?, @scope[:shallow], options)
159+
160+
jsonapi_resource_scope(resource_arg, @resource_type) do
137161
if block_given?
138162
yield
139163
else
@@ -277,7 +301,7 @@ def jsonapi_resource_scope(resource, resource_type) #:nodoc:
277301
private
278302

279303
def resource_type_with_module_prefix(resource = nil)
280-
resource_name = resource || @scope[:jsonapi_resource]
304+
resource_name = resource || @scope[:jsonapi_resource] || @jsonapi_resource_type
281305
[@scope[:module], resource_name].compact.collect(&:to_s).join('/')
282306
end
283307
end

0 commit comments

Comments
 (0)