Slide 1

Slide 1 text

現実の RUBY/RAILSアップグレード外伝 そして僕はFORKした KAIGI ON RAILS 2024 事後勉強会 @TAKEYUWEB

Slide 2

Slide 2 text

スピーカーについて ● @takeyuweb ● フリーランス→法人成り ● Rails 1.1 ~ ● アップグレード経験多数 ● Kaigi on Rails 2024 登壇

Slide 3

Slide 3 text

問題と解決 問題 • Gemの更新が止まってる • 新しいバージョンで 動かない • 依存関係を解決できない 解決 • Forkして自分で保守する • 別のgemに置き換える 保守されていないGEM refile globalize

Slide 4

Slide 4 text

GLOBALIZE ● 多言語化用gem ● ふつうのActiveRecordのような手触りで 多言語化を実現できる class People < ApplicationRecord translates :greeting end people = People.new people.attributes = { greeting: "こんにちは、世界" , locale: :ja } people.attributes = { greeting: "Hello, World", locale: :en } people.save I18n.locale = :ja people.greeting # => "こんにちは、世界" I18n.locale = :en people.greeting # => "Hello, World"

Slide 5

Slide 5 text

GLOBALIZE ● Rails 7.1~ ● Passing the class as positional argument is deprecated and will be removed in Rails 7.2. “位置引数としてクラスを渡すことは非推奨となり、Rails7.2で削除される予定です”

Slide 6

Slide 6 text

GLOBALIZE ● ActiveRecord Serialization で第二引数としてcoderクラスを渡す書き方が非推奨となった ○ coder: キーワード引数で渡す ● アプリケーションを修正しても、警告が消えない ● globalize gemに原因があった # Rails 7.0まで class User < ApplicationRecord serialize :preferences, JSON end # Rails 7.1から class User < ApplicationRecord serialize :preferences, coder: JSON end

Slide 7

Slide 7 text

GLOBALIZE ● serialize メソッドをオーバーライドしていた ● Rails 7.1用の修正が必要 ● 修正があるかgithubを確認する module Globalize module AttributeMethods module Serialization def serialize(attr_name, class_name_or_coder = Object, **options) super(attr_name, class_name_or_coder, **options) # これ! # 省略 end end end end ActiveRecord::AttributeMethods::Serialization::ClassMethods .send(:prepend, Globalize::AttributeMethods::Serialization) 翻訳を意識せずに使える のは責務の分離の観点で よさそうだが、その実現の ためバージョン分岐しての モンキーパッチなどで壊れ やすくてつらい

Slide 8

Slide 8 text

GLOBALIZE ● …, but none of the maintainers actively use Globalize anymore. “もはやGlobalizeを積極的に使用しているメンテナはいません”

Slide 9

Slide 9 text

GLOBALIZE ● …, but none of the maintainers actively use Globalize anymore. “もはやGlobalizeを積極的に使用しているメンテナはいません” ● やめたい ● やめるのは簡単でなさそう ○ アプリケーション全体で使われている ○ 影響箇所がわかりづらい ○ やめるプロジェクトも進めているが、いますぐは…

Slide 10

Slide 10 text

GLOBALIZE ● 仕方ないのでForkする ● 問題のコードをRails 7.1用に修正 ○ 取り込まれていないが修正PRがあった ○ 取り込んだ ● その後7.2でテストを実行するとエラー ○ 別の問題 ○ ActiveSupport::Deprecationの シングルトン利用が非推奨化 ○ 自分で変更 ■ ActiveSupport::Deprecation.silence ■ ActiveSupport.deprecator.silence module Globalize module AttributeMethods module Serialization def serialize(attr_name, class_name_or_coder = Object, **options) if options[:coder].blank? if class_name_or_coder == ::JSON || [ :load, :dump ].all? { |x| class_name_or_coder.respond_to?(x) } options = options.merge(coder: class_name_or_coder, type: Object) else options = options.merge(coder: default_column_serializer, type: class_name_or_coder) end end super(attr_name, **options)

Slide 11

Slide 11 text

REFILE ● ファイルアップロード機能を提供するgem ● ActiveStorage以前のアップローダーgem ● 長らくメンテされていない ○ 実用的な機能は一通りある ■ クラウドストレージ ■ CDN ● ファイルアップロード機能の乗り換えは大変 ○ たとえば ■ これまでにアップロードされた資産の扱い ■ 配信や変換の仕組み

Slide 12

Slide 12 text

REFILE ● Ruby 3.0 のキーワード引数の非互換性で壊れる ● 修正方法は呼び出し側にダブルスプレッドをつければいい # 第三引数にハッシュを渡して @template.attachment_field( @object_name, method, objectify_options(options) ) # object: と options ハッシュで受け取っている def attachment_field(object_name, method, object:, **options) # こうすれば動く @template.attachment_field( @object_name, method, **objectify_options(options) )

Slide 13

Slide 13 text

REFILE ● 長らくメンテされていない(2回目)

Slide 14

Slide 14 text

REFILE ● 仕方がないのでforkする(2回目)

Slide 15

Slide 15 text

REFILE-S3 ● refileのプラグイン ● S3バックエンド ● Ruby 3.0で壊れる ● open-uri の変更 ○ RUby 2.7まで`require 'open-uri'` すると、 `Kernel.open` を拡張していたが、3.0ではなくなった ● Refile同様放置 ● 仕方ないのでfork # これを Kernel.open(object(id).presigned_url(:get)) # こうする URI.open(object(id).presigned_url(:get))

Slide 16

Slide 16 text

WICKED_PDF (FORKしなかった) ● RailsのビューをPDFとして返せるようにするやつ ● wkhtmltopdfのラッパー ● wkhtmltopdfは開発終了 ○ Qt WebKitを使ってレンダリング ○ Qt WebKitの開発が止まってしまった ● 移行先が課題

Slide 17

Slide 17 text

WICKED_PDF (FORKしなかった) 独自のDSL prawn 専用のエデ ィター Thinreports HTMLをPDF に変換 wicked_pdf grover (puppeteer) Ferrum (pureruby)

Slide 18

Slide 18 text

WICKED_PDF (FORKしなかった) ● ferrum gem ○ render メソッドの調整で移行できた ● wicked_pdfと同じく、RailsのビューをレンダリングしてPDFとして印刷する仕組み ○ wicked_pdf QtWebKit ○ ferrum Chronium ■ 環境に入れたChromiumのバージョンが古くてフォントのフルセットが埋め込まれる事故が発生 ■ Chromiumのバージョンアップで解消

Slide 19

Slide 19 text

FORKは最後の手段 ● やむなくfork ○ 修正が必要 ○ メンテナンスされていない ○ 移行が簡単ではない

Slide 20

Slide 20 text

FORKし(たりし)て思ったこと つらい 多機能・高機能なgem “標準”の振る舞いを変えてくるgem 全体と密結合するgem なんとかなる 軽量(薄い)なgem 境界がはっきりとわかるgem

Slide 21

Slide 21 text

GEMの選び方 ● 自分が保守できるか? ○ 多機能ではない ○ メタプログラミングはほどほどに ○ 標準の動きを変えない ● 保守できないなら ○ 継続性はありそうか? ■専門知識が必要なgemは自分で保守が難しい ■コントリビューションがありそうか ■完成していて更新の必要がないものはなくてもok ○ 置き換えできそうか ■更新が止まっても代替手段へ切り替えでしのげること ■シンプルであること アップグレードしていくために gemの 依存gem も注意 開発に専門知識が 必要なgemは置換え しやすそうな作りが 大切