Skip to content

Support Ruby 3.3, 3.4, 4.0 and Rails 8.1, and fix rake api_spec on Rails 7.0+ - #20

Draft
snhrm wants to merge 6 commits into
masterfrom
chore/support-ruby-4-0-rails-8-1
Draft

snhrm wants to merge 6 commits into
masterfrom
chore/support-ruby-4-0-rails-8-1

Conversation

@snhrm

@snhrm snhrm commented Oct 30, 2026 •

Copy link
Copy Markdown

Why

  • アプリを Ruby 3.4 / 4.0、Rails 8.1 に上げられるようにするため。現在の 0.6.1 は actionpack / railties < 7.2 になっている
  • rake api_spec が Rails 7.0 以降、NoMethodError: undefined method 'type' for an instance of ActionDispatch::Journey::Ast で失敗する
  • wantedly で rake api_spec を実行して見つかった、既存のバグ 2 つ
    • serializer: を指定した belongs_to の $ref が、#/components/schemas/["OpenUser"] のように配列を文字列にしたものになる
    • has_many の type: に配列ではなくクラスなどを書いた serializer が 1 つでもあると、rake api_spec が止まるか、不正な $ref を出力する。ActiveRecord のモデルを書いた場合、テーブルが空なら TypeError: no implicit conversion of nil into Hash で止まる

What

  • RoutesFinder が route.path.ast ではなく route.path.spec を使うように直す
    • Rails 7.0 以降の Pattern#ast は Journey::Ast というラッパーを返し、eager_load! の後は nil になる
    • Pattern#spec は Rails 5.0〜8.1 のどの版でも、生のノードツリーを返す
  • Rails が実際に描いた RouteSet を使う spec を追加する。既存の spec は Rails を全部 mock しているので、この不具合を検出できなかった
  • open_api_belongs_to_associations で、serializer: を指定したときの型を配列で包まないようにする
    • has_many の行をコピーしたまま [...] が残っていた。has_one は配列で包んでいない
  • ComponentsBuilder で、has_many の型が配列でないか空の配列のときは、警告を出してその関連だけを飛ばす
    • これまでは each の中の return でメソッド全体が nil を返し、merge!(nil) で TypeError になっていた
    • first は型が配列のときだけ呼ぶようにした。ActiveRecord のモデルだと first が DB クエリを実行し、データがあればレコードが返って不正な $ref が出力されるため。文字列 ("Author") でも ActiveSupport の String#first で "A" が返っていた
  • actionpack / railties の上限を < 8.2 にし、open_api >= 0.6.3 を必須にする
    • open_api 0.6.3 には、forwardable を明示的に require する修正 (Support Ruby 3.3, 3.4, 4.0 and Rails 8.1 open_api#18) も入っている
    • この修正が無いと、Ruby 3.3 以降では Rails アプリの外で require "open_api_annotator" したときに NameError: uninitialized constant OpenApi::Paths::Forwardable になる。open_api_annotator が require "rails" の直後に require "open_api" するため
    • Rails アプリの中では action_controller が先に forwardable を読み込むので、表に出ていなかった。この gem の spec でも、spec_helper が先に読む simplecov が forwardable を読み込むので検出できていなかった
  • 開発依存の bundler ~> 2.0 を削除し、CI を Ruby 3.3 / 3.4 / 4.0 と Rails 7.0〜8.1 にし、Code Climate を削除する。どれも Support Ruby 3.3, 3.4, 4.0 and Rails 8.1 open_api#18 と同じ内容
  • 0.6.2 に上げ、CHANGELOG を追記する

確認したこと

  • spec が全件通る (18 examples, 0 failures)
    • 対象は、Ruby 3.3 / 3.4 / 4.0 × Rails 7.0〜8.1
    • open_api はローカルの 0.6.3 を使った
  • 追加した spec は、.ast / .ast.root に戻す変異や、パラメータを落とす変異で落ちる
  • 既存バグの修正の spec は、次の変異でそれぞれ落ちる (Ruby 3.3 / 4.0)
    • belongs_to の型を配列で包む / has_one の型を配列で包む / has_many の型の [...] を外す
    • next を return に戻す
    • 配列かどうかの判定を外す / クラスかどうかの判定に変える
    • 警告を外す / 警告文から型を外す
    • スキップ処理ごと外す
  • Ruby 3.3 / 4.0 で、Support Ruby 3.3, 3.4, 4.0 and Rails 8.1 open_api#18 の open_api なら require "open_api_annotator" が通り、修正前の open_api では NameError になる
  • RoutesFinder の修正について、ダミーの Rails アプリで rake api_spec を実行した (既存バグの修正の確認は下の「wantedly での確認」)
    • 対象は、Rails 7.0〜8.1 × Ruby 3.3 / 3.4 / 4.0、eager_load の有無の両方
    • 生成された YAML は、Rails 6.1 で修正前のコードが出したものと一致した

wantedly での確認

wantedly master のコピーに wantedly/open_api#18 とこの PR の gem を入れ、development 環境で rake api_spec:create を実行した。

  • wantedly/wantedly#81643 (CandidacySerializer の has_many :selection_invitation_logs の type: を配列にする 1 行。wantedly/wantedly#73734 (2025-05-20) からクラスになっていた) を当てた場合
    • exit 0 (paths 139 / schemas 122)
    • コミット済みの swagger/api_v2.yml と比べて、既存の path と、既存 schema の既存プロパティは、Api::ProjectRecommendation の supporter の $ref が #/components/schemas/OpenUser に直ったこと以外は一致した
    • それ以外の差分は、2025-05 以降に追加された path 10 本・schema 7 個・既存 schema へのプロパティ 15 個と、wantedly/wantedly#81500 で消し残っていた AttachmentFile schema の削除だけ
  • wantedly/wantedly#81643 を当てない場合
    • exit 0 で通るが、Skipped CandidacySerializer#selection_invitation_logs: ... の警告が出て、Candidacy の selection_invitation_logs だけが出力から抜ける
    • 正しい定義を出すには、wantedly/wantedly#81643 が必要

merge の順番

  1. Support Ruby 3.3, 3.4, 4.0 and Rails 8.1 open_api#18 を merge して、0.6.3 をリリースする
  2. この PR の CI を再実行する。0.6.3 が公開されるまでは、open_api >= 0.6.3 を解決できずに全セルが失敗する
  3. merge して bundle exec rake release を実行する
  4. wantedly で両方の gem を上げ、wantedly/wantedly#81643 が入った状態で rake api_spec:create を実行して swagger/api_v2.yml を再生成する

snhrm added 4 commits October 29, 2026 23:22
Since Rails 7.0, Journey::Path::Pattern#ast returns a Journey::Ast wrapper
(and is cleared on eager_load!), so PathResolver failed on ast.type.
Pattern#spec returns the raw node tree on every Rails version.
- Relax actionpack / railties upper bound to < 8.2
- Require open_api >= 0.6.3, the first version allowing activesupport 7.2+
- Drop bundler ~> 2.0 dev dependency, which conflicts with Bundler 4 bundled with Ruby 4.0
- Test Ruby 3.3, 3.4, 4.0 and Rails 7.0 to 8.1 on CI
- Remove Code Climate coverage upload, whose API was shut down
Comment on lines +16 to 17
- ruby: "3.3"
gemfile: "gemfiles/rails-7.0.gemfile"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wantedly/open_api#18 では 7ad9e95 で Ruby 4.0 × rails-7.0 のセルを追加していますが、こちらには入っていないようです。
annotator は railties / actionpack も読み込むので、対応表の中では Ruby 4.0 × Rails 7.0 がいちばん壊れやすい組み合わせだと思います (手元では spec は通りますが、Rails 7.0 から tsort の deprecation warning が出ます)。open_api#18 に揃えて追加しておくのはどうでしょう。

Suggested change
- ruby: "3.3"
gemfile: "gemfiles/rails-7.0.gemfile"
- ruby: "3.3"
gemfile: "gemfiles/rails-7.0.gemfile"
- ruby: "4.0"
gemfile: "gemfiles/rails-7.0.gemfile"

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ありがとうございます、open_api#18 に揃えて Ruby 4.0 × rails-7.0 のセルを追加しました (c1abd20)。
手元 (Docker) でも Ruby 4.0.9 × railties 7.0.10 で 13 examples, 0 failures を確認しています。tsort の warning は railties 7.0 の rails/initializable.rb 由来で 7.1 以降では出ないため、今回はそのままにしています。
なお open_api 0.6.3 の公開前なので、このセルも他と同様に依存解決で落ちる状態です。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ご対応ありがとうございます、c1abd20 を確認しました。LGTM です。
open_api#18 の merge と 0.6.3 のリリース後に、こちらの CI を再実行して通ったことを確認してから approve します。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

追加の 664f4e8 (belongs_to の $ref の修正と、配列でない has_many のスキップ) も確認しました。こちらも LGTM です。
approve は前回書いたとおり、open_api 0.6.3 のリリース後に CI が通ったことを確認してから行います。

@snhrm

snhrm commented Nov 6, 2026

Copy link
Copy Markdown
Author

wantedly で動作確認したところ、この PR だけでは wantedly の rake api_spec:create が最後まで通らないことが分かったので、本文に「wantedly で rake api_spec を通すには、wantedly 側の修正も必要」の節を追記しました。

  • この PR で path の生成は通るようになりますが、schema の生成で TypeError: no implicit conversion of nil into Hash になります
  • 原因は wantedly の CandidacySerializer の has_many :selection_invitation_logs, type: SelectionInvitationLog (配列ではなくクラス) で、wantedly/wantedly#73734 (2025-05-20) から壊れていました
  • wantedly 側の修正は wantedly/wantedly#81643 です (1 行、API のレスポンスは変わりません)
  • #81643 も当てた wantedly master のコピーでは rake api_spec:create が exit 0 で通り、既存の path / schema の出力はコミット済みの swagger/api_v2.yml と一致しました

この PR の変更内容自体は変わっていません。

… type

- open_api_belongs_to_associations wrapped the serializer's resource name
  in an array, producing $ref like #/components/schemas/["OpenUser"].
- build_has_many_association_properties called first on the annotated
  type even when it was not an array (e.g. an ActiveRecord model, which
  runs a query), and returned nil from the whole method when it got nil,
  making rake api_spec raise TypeError. Now it calls first only on arrays
  and skips the association with a warning otherwise.
@snhrm

snhrm commented Nov 6, 2026

Copy link
Copy Markdown
Author

LGTM いただいた後ですが、wantedly で rake api_spec を動かして見つかった既存バグ 2 件の修正を、この PR に追加しました (664f4e8)。

  • serializer: を指定した belongs_to の $ref が #/components/schemas/["OpenUser"] になっていたのを直しました
  • has_many の type: が配列でない場合 (wantedly の CandidacySerializer のように) に rake api_spec が TypeError で止まっていたので、警告を出してその関連だけを飛ばすようにしました

詳細は本文の What と「wantedly での確認」に追記しています。お手数ですが、差分 (lib 2 ファイルと spec) の確認をお願いします。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants