Skip to content

Commit b02076a

Browse files
MaicolBenclaude
andauthored
Support Rails 8.0 and 8.1 (#1686)
* Support Rails 8.0 and 8.1 The gemspec already allowed Rails 8.1 (`< 8.2`), but nothing in CI exercised anything newer than Rails 7.0, so support past 7.0 was asserted rather than verified. This adds real coverage. - Add gemfiles/rails_8_0.gemfile and gemfiles/rails_8_1.gemfile, with the Rails version pinned to the minor (`~> 8.0.0` / `~> 8.1.0`) so each job tests the version it names. - Add matching Appraisals entries. - Add both gemfiles to the CI matrix, excluding Ruby < 3.2 since Rails 8 requires Ruby >= 3.2. - Use `check_all_pending!` in the test helper when available; `check_pending!` was deprecated in Rails 7.1 and removed in Rails 8.0. - Widen the sqlite3 dev dependency, since Rails 8 needs sqlite3 2.x. - Widen the mongoid dev dependency ceiling to `< 10`; mongoid 7.x caps activemodel at `< 6.1`, which makes Rails 8 unresolvable. - Bump the rails ceiling to `< 8.3` so 8.2 is allowed when it ships. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Pin each gemfile to the Rails version it names The gemfiles used `~> 7.0`-style constraints, which allow any 7.x. They only resolved to the version in their filename because the `mongoid '< 8'` dev dependency transitively capped activemodel and held Rails down. Widening that ceiling for Rails 8 removed the cap, and rails_7_0.gemfile silently began resolving to Rails 7.2 — which is what made the omniauth tests fail. Pin to the minor (`~> 7.0.0`) so each job tests the version it claims and resolution cannot drift when an unrelated dependency changes. * Revert "Pin each gemfile to the Rails version it names" This reverts commit 6aba91b. * Pin only the Rails 7.0 gemfiles The blanket pin regressed rails_6_0.gemfile: it has been resolving to Rails 6.1 all along, and the dummy app's legacy_connection_handling= setting does not exist in real 6.0, so pinning it broke a previously green row. Pin only rails_7_0*, which needs it because widening the mongoid ceiling removes the transitive cap that used to hold it at 7.0. * Replace CGI.parse in the omniauth redirect for Ruby 3.5 / Rails 8.1 `CGI.parse` is no longer available in the cgi gem shipped with Ruby 3.5, which Rails 8.1 pulls in. Every omniauth test errors with `undefined method 'parse' for class CGI` at routes.rb:79. Use `Rack::Utils.parse_query` instead. It returns a bare value for single occurrences where `CGI.parse` returned a one-element array, so normalize with `Array()` — downstream code does `qs['x'] = [resource]` and `v.first` and depends on that shape. Verified equivalent to `CGI.parse` for the inputs this route sees, including repeated keys, bare keys, empty values, empty strings and percent-encoded reserved characters. The only divergence is the legacy `;` separator, which `Rack::Utils.parse_query` does not split on; that form is long deprecated and does not occur in omniauth callbacks. Rack is always loaded here since this file reopens ActionDispatch::Routing::Mapper. * Rewind the request body before re-reading it in the omniauth redirect For POSTed omniauth requests the route falls back to `request.body.read` when QUERY_STRING is empty. As of Rails 7.1 the body has typically already been consumed by the time this redirect block runs, so `read` returns "" and every param — auth_origin_url, omniauth_window_type, resource_class — is silently dropped. Rewind before reading. Guarded with respond_to? since not every rack input is rewindable. * Fix two test-side assumptions broken by newer Rails Neither is a library bug; both are test expectations that no longer match Rails behaviour. 1. Rails 7.2 changed `redirect_to` to set an empty response body instead of the "You are being redirected" HTML snippet, so the confirmations tests could no longer find the redirect URL in `response.body`. Assert against `response.location`, which carries the same URL on every supported version. 2. The dummy app's show_exceptions guard read `MAJOR >= 7 && MINOR > 0`, which is false on Rails 8.0 (MINOR == 0), so it set the pre-7.1 `false` value. Rails 7.1+ treats this setting as an enum and an unrecognised value falls through to "render exceptions", so the four `assert_raises` tests saw a rendered error page instead of a raised exception. Compare with Rails.gem_version instead. This is why those tests failed on 8.0 but not 8.1. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent ec19d94 commit b02076a

11 files changed

Lines changed: 157 additions & 12 deletions

File tree

.github/workflows/test.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ jobs:
2323
- gemfiles/rails_5_2.gemfile
2424
- gemfiles/rails_6_0.gemfile
2525
- gemfiles/rails_7_0.gemfile
26+
- gemfiles/rails_8_0.gemfile
27+
- gemfiles/rails_8_1.gemfile
2628
db:
2729
- sqlite
2830
- mysql
@@ -122,6 +124,19 @@ jobs:
122124
gemfile: gemfiles/rails_5_2.gemfile
123125
- ruby: 3.4
124126
gemfile: gemfiles/rails_6_0.gemfile
127+
# Rails 8 requires Ruby >= 3.2
128+
- ruby: 2.7
129+
gemfile: gemfiles/rails_8_0.gemfile
130+
- ruby: 2.7
131+
gemfile: gemfiles/rails_8_1.gemfile
132+
- ruby: '3.0'
133+
gemfile: gemfiles/rails_8_0.gemfile
134+
- ruby: '3.0'
135+
gemfile: gemfiles/rails_8_1.gemfile
136+
- ruby: 3.1
137+
gemfile: gemfiles/rails_8_0.gemfile
138+
- ruby: 3.1
139+
gemfile: gemfiles/rails_8_1.gemfile
125140

126141
services:
127142
mysql:

Appraisals

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,20 @@ end
4444
gem 'mongoid-locker', '~> 1.0'
4545
end
4646
end
47+
48+
[
49+
{ name: '8-0', version: '8.0' },
50+
{ name: '8-1', version: '8.1' }
51+
].each do |rails|
52+
appraise "rails-#{rails[:name]}" do
53+
gem 'rails', "~> #{rails[:version]}.0"
54+
55+
gem 'sqlite3', '~> 2.1'
56+
gem 'mysql2'
57+
gem 'pg'
58+
59+
group :development, :test do
60+
gem 'minitest-rails', "~> #{rails[:version]}"
61+
end
62+
end
63+
end

devise_token_auth.gemspec

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ Gem::Specification.new do |s|
2222

2323
s.required_ruby_version = ">= 2.3.0"
2424

25-
s.add_dependency 'rails', '>= 4.2.0', '< 8.2'
25+
s.add_dependency 'rails', '>= 4.2.0', '< 8.3'
2626
s.add_dependency 'devise', '> 3.5.2', '< 6'
2727
s.add_dependency 'bcrypt', '~> 3.0'
2828

2929
s.add_development_dependency 'appraisal'
30-
s.add_development_dependency 'sqlite3', '~> 1.4'
30+
s.add_development_dependency 'sqlite3', '>= 1.4', '< 3.0'
3131
s.add_development_dependency 'pg'
3232
s.add_development_dependency 'mysql2'
33-
s.add_development_dependency 'mongoid', '>= 4', '< 8'
33+
s.add_development_dependency 'mongoid', '>= 4', '< 10'
3434
s.add_development_dependency 'mongoid-locker', '>= 1.0', '< 3.0'
3535
end

gemfiles/rails_7_0.gemfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ source "https://rubygems.org"
44

55
gem "omniauth", "~> 2.0"
66
gem "omniauth-rails_csrf_protection"
7-
gem "rails", "~> 7.0"
7+
gem "rails", "~> 7.0.0"
88
gem "sqlite3", "~> 1.4.1"
99
gem "mysql2"
1010
gem "pg"

gemfiles/rails_7_0_mongoid_7.gemfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
source "https://rubygems.org"
44

55
gem "omniauth", "~> 2.0"
6-
gem "rails", "~> 7.0"
6+
gem "rails", "~> 7.0.0"
77
gem "omniauth-rails_csrf_protection"
88
gem "mongoid", "~> 7.0"
99
gem "mongoid-locker", "~> 1.0"

gemfiles/rails_8_0.gemfile

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# This file was generated by Appraisal
2+
3+
source "https://rubygems.org"
4+
5+
gem "omniauth", "~> 2.0"
6+
gem "omniauth-rails_csrf_protection"
7+
gem "rails", "~> 8.0.0"
8+
gem "sqlite3", "~> 2.1"
9+
gem "mysql2"
10+
gem "pg"
11+
12+
group :development, :test do
13+
gem "attr_encrypted"
14+
gem "figaro", "~> 1.2"
15+
gem "omniauth-facebook"
16+
gem "omniauth-github"
17+
gem "omniauth-google-oauth2"
18+
gem "omniauth-apple"
19+
gem "rack-cors"
20+
gem "thor", "~> 1.2"
21+
gem "database_cleaner"
22+
gem "factory_bot_rails"
23+
gem "faker", "~> 3.2"
24+
gem "fuzz_ball"
25+
gem "minitest"
26+
gem "minitest-focus"
27+
gem "minitest-rails", "~> 8.0"
28+
gem "minitest-reporters"
29+
gem "mocha", ">= 1.5"
30+
gem "pry"
31+
gem "pry-byebug"
32+
gem "pry-remote"
33+
gem "rubocop", require: false
34+
end
35+
36+
group :test do
37+
gem "rails-controller-testing"
38+
gem "simplecov", require: false
39+
end
40+
41+
group :development do
42+
gem "github_changelog_generator"
43+
end
44+
45+
gemspec path: "../"

gemfiles/rails_8_1.gemfile

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# This file was generated by Appraisal
2+
3+
source "https://rubygems.org"
4+
5+
gem "omniauth", "~> 2.0"
6+
gem "omniauth-rails_csrf_protection"
7+
gem "rails", "~> 8.1.0"
8+
gem "sqlite3", "~> 2.1"
9+
gem "mysql2"
10+
gem "pg"
11+
12+
group :development, :test do
13+
gem "attr_encrypted"
14+
gem "figaro", "~> 1.2"
15+
gem "omniauth-facebook"
16+
gem "omniauth-github"
17+
gem "omniauth-google-oauth2"
18+
gem "omniauth-apple"
19+
gem "rack-cors"
20+
gem "thor", "~> 1.2"
21+
gem "database_cleaner"
22+
gem "factory_bot_rails"
23+
gem "faker", "~> 3.2"
24+
gem "fuzz_ball"
25+
gem "minitest"
26+
gem "minitest-focus"
27+
gem "minitest-rails", "~> 8.1"
28+
gem "minitest-reporters"
29+
gem "mocha", ">= 1.5"
30+
gem "pry"
31+
gem "pry-byebug"
32+
gem "pry-remote"
33+
gem "rubocop", require: false
34+
end
35+
36+
group :test do
37+
gem "rails-controller-testing"
38+
gem "simplecov", require: false
39+
end
40+
41+
group :development do
42+
gem "github_changelog_generator"
43+
end
44+
45+
gemspec path: "../"

lib/devise_token_auth/rails/routes.rb

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,20 @@ def mount_devise_token_auth_for(resource, opts)
7676
match "#{full_path}/:provider", to: redirect(status: 307) { |params, request|
7777
# get the current querystring
7878
# TODO: deprecate in favor of using params
79-
qs = CGI::parse(request.env['QUERY_STRING'].empty? ? request.body.read : request.env['QUERY_STRING'] )
79+
# `CGI.parse` is unavailable as of the cgi gem shipped with Ruby 3.5
80+
# (pulled in by Rails 8.1). `Rack::Utils.parse_query` returns a bare
81+
# value for single occurrences, so normalize to arrays to keep the
82+
# shape `CGI.parse` returned.
83+
# As of Rails 7.1 the request body may already have been read when
84+
# this runs, in which case `read` returns "" and every param is
85+
# silently dropped. Rewind first so POSTed params survive.
86+
query_string = if request.env['QUERY_STRING'].empty?
87+
request.body.rewind if request.body.respond_to?(:rewind)
88+
request.body.read
89+
else
90+
request.env['QUERY_STRING']
91+
end
92+
qs = Rack::Utils.parse_query(query_string).transform_values { |v| Array(v) }
8093

8194
# append name of current resource
8295
qs['resource_class'] = [resource]

test/controllers/devise_token_auth/confirmations_controller_test.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ def token_and_client_config_from(body)
6262
end
6363

6464
test 'redirect url includes token params' do
65-
assert @token_params.all? { |param| response.body.include?(param) }
66-
assert response.body.include?('account_confirmation_success')
65+
assert @token_params.all? { |param| response.location.include?(param) }
66+
assert response.location.include?('account_confirmation_success')
6767
end
6868
end
6969

@@ -86,8 +86,8 @@ def token_and_client_config_from(body)
8686
end
8787

8888
test 'redirect url does not include token params' do
89-
refute @token_params.any? { |param| response.body.include?(param) }
90-
assert response.body.include?('account_confirmation_success')
89+
refute @token_params.any? { |param| response.location.include?(param) }
90+
assert response.location.include?('account_confirmation_success')
9191
end
9292
end
9393

test/dummy/config/environments/test.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@
3232
config.action_controller.perform_caching = false
3333

3434
# Raise exceptions instead of rendering exception templates.
35-
if Rails::VERSION::MAJOR >= 7 && Rails::VERSION::MINOR > 0
35+
# Rails 7.1 turned this into an enum; `false` is no longer recognised and
36+
# falls through to the "show everything" default. Note the version check must
37+
# not be `MAJOR >= 7 && MINOR > 0`, which is false on Rails 8.0.
38+
if Rails.gem_version >= Gem::Version.new('7.1')
3639
config.action_dispatch.show_exceptions = :none
3740
else
3841
config.action_dispatch.show_exceptions = false

0 commit comments

Comments
 (0)