Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

週刊Railsウォッチ: スライド『Rails 7.1をn倍速くした話』、Rails 7.1でMessagePackをサポートほか(20230502)

こんにちは、hachi8833です。RubyKaigi 2023のグルメ情報も出ましたね。

週刊Railsウォッチについて

  • 各記事冒頭には🔗でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
  • お気づきの点がありましたら@hachi8833までメンションをいただければ確認・対応いたします🙏

TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)

お知らせ: 次回の週刊Railsウォッチは5/23(火)の予定です。

🔗Rails: 先週の改修(Rails公式ニュースより)

🔗 複合主キー関連

🔗 複合主キーでレコードを関連付けから削除可能になった

動機/背景
複合主キーをサポートする継続的取り組みの一環。

この変更によって、複合コンテキストにおける関連付けからのレコード削除が正しく実装される。

詳細

この変更が行われないと以下のようになる。

great_author = cpk_authors(:cpk_great_author)
books = great_author.books

# ArgumentError (Expected corresponding value for [:author_id, :number] to be an Array)
great_author.books.delete(books.first)

これは、composite_query_constraints_listを用いて配列内でクエリ制約(主キー)を取得してから、渡されたレコードから対応するカラムをSELECTできるようにする。

従来は、多くのケースがwhere(id => [records])に解決し、最終的にArrayHandlerのロジックを用いてidがデフォルトになっていた

これは、複合主キーのシナリオをサポートするためにIDへの解決がより早い段階で行われることを除けば同じである。

注: マルチテナンシーでは、主キーだけではなくクエリ制約を用いてレコードを削除する必要が生じるシナリオが存在するため、クラスでquery_constraints_listを使うことが重要。
同PRより


つっつきボイス:「dependentオプションで指定したモデルのレコードを芋づる式に削除する機能がActive Recordに標準でありますけど、それを複合主キーでもできるようになった👍」「複合主キーを標準機能でサポートするとフレームワーク側でいろいろ改修しないといけなくなるのか、大変そう」「キーが使われる場所全部で複合主キーに対応する必要があるからそうなりますよね」

参考: Active Record の関連付け - Railsガイド

🔗 ids_writerids_readerで複合主キーをサポート

ids_writerが複合主キー(CPK)を扱えるように修正する。
非複合主キーモデルに関連付けられている複合主キーモデルを使う場合は正しく動作していた(これ用のテストも追加しておいた)が、別の複合主キーモデルに関連付けられているCPKモデルを使う場合は正しく動作していなかった。この修正によって、正しいidの書き込みにも配慮するようになった。

ids_readerで作業していて、pluckメソッドが複合主キーで動作しないことに気づいた。理由は、これが属性の配列を渡していて、disallow_raw_sql!ではサポートされていないため。
他の場所でも同様の問題が起きていそうだったので、pluck内でflattenを呼び出すことにした。これによって複合主キーによるpluck全体が修正され、計算のテストファイルも修正できた。
同PRより


つっつきボイス:「has_manyを使うと複数形の何ちゃら_idsメソッドや何ちゃら_ids=メソッドが生えてくる機能が前からあったのか」「これ使ったことなかったかも」「その機能を複合主キーに対応したんですね」

参考: §20.3 ids -- Active Record クエリインターフェイス - Railsガイド

ids_writerの定義はこれですね↓」

# activerecord/lib/active_record/associations/collection_association.rb#L60
      def ids_writer(ids)
        primary_key = reflection.association_primary_key
        pk_type = klass.type_for_attribute(primary_key)
        ids = Array(ids).compact_blank
        ids.map! { |i| pk_type.cast(i) }

-       records = klass.where(primary_key => ids).index_by do |r|
-         r.public_send(primary_key)
+       records = if klass.composite_primary_key?
+         query_records = ids.map { |values_set| klass.where(primary_key.zip(values_set).to_h) }.inject(&:or)
+
+         query_records.index_by do |r|
+           primary_key.map { |pk| r.public_send(pk) }
+         end
+       else
+         klass.where(primary_key => ids).index_by do |r|
+           r.public_send(primary_key)
+         end
        end.values_at(*ids).compact

        if records.size != ids.size
          found_ids = records.map { |record| record.public_send(primary_key) }
          not_found_ids = ids - found_ids
          klass.all.raise_record_not_found_exception!(ids, records.size, ids.size, primary_key, not_found_ids)
        else
          replace(records)
        end
      end

🔗 バッチ処理で複合主キーをサポート

従来のバッチ処理は、シンプルな主キーを持つテーブルでしか動作しなかった。

実装の説明

複合主キーの現在のタプル(a, b)を昇順でイテレートする場合、以下のタプル(ここでは(x, y)とする)を取得するSQL条件は以下の数式で計算される。

(x, y) > (a, b) iff x > a OR (x = a AND y > b)

何らかのタプルから開始する場合は、これと似た以下の式で計算される。

(x, y) >= (a, b) iff x > a OR (x = a AND y >= b)

複合主キーにカラムが3つ以上ある場合も、類似のロジックが適用される。
同PRより


つっつきボイス:「バッチ処理用のin_batchesというメソッドを複合主キーに対応するために、batch_orderの部分ですべての複合主キーにORDERが効くようにしている↓: ORDERのキーが1つだと順序が固定されないので」「こうしてみるとActive Recordに全面的に手を入れているのがわかりますね」「複合主キーが7.1に入るとしたらきっと目玉機能になりそう」

# activerecord/lib/active_record/relation/batches.rb#L230
-     relation = relation.reorder(batch_order(order)).limit(batch_limit)
+     relation = relation.reorder(*batch_order(order)).limit(batch_limit)
+     relation = apply_limits(relation, start, finish, order)
+     relation.skip_query_cache! # Retaining the results in the query cache would undermine the point of batching
+     batch_relation = relation
+     empty_scope = to_sql == klass.unscoped.all.to_sql

      loop do
        if load
          records = batch_relation.records
          ids = records.map(&:id)
          yielded_relation = where(primary_key => ids)
          yielded_relation.load_records(records)
        elsif (empty_scope && use_ranges != false) || use_ranges
-         ids = batch_relation.pluck(primary_key)
+         ids = batch_relation.ids
          finish = ids.last
          if finish
            yielded_relation = apply_finish_limit(batch_relation, finish, order)
            yielded_relation = yielded_relation.except(:limit, :order)
            yielded_relation.skip_query_cache!(false)
          end
        else
-         ids = batch_relation.pluck(primary_key)
+         ids = batch_relation.ids
          yielded_relation = where(primary_key => ids)
        end

参考: Rails API in_batches -- ActiveRecord::Batches

🔗 Trilogyデータベースクライアント用のアダプタが導入される

TrilogyはMySQLと互換性のあるデータベースクライアント。
Railsアプリケーションでconfig/database.ymlを以下のように設定することでTrilogyを利用できる。

development:
adapter: trilogy
database: blog_development
pool: 5

以下のようにDATABASE_URL環境変数でも設定できる。

ENV['DATABASE_URL'] # => "trilogy://localhost/blog_development?pool=5"

Adrianna Chang
同Changelogより


動機/背景
Trilogyデータベースクライアントに対応するActive Recordアダプタが昨年GitHubによってオープンソース化された。Shopifyも数週間前に自社のRailsモノリスでTrilogyの採用に成功した。

2つのメジャーなRailsアプリケーションでTrilogyが正常に動作しているので、これをMysql2Adapterに代わるMySQL互換のアダプタとしてアップストリームのRailsにマージすることを提案したい。

なお、この取り組みはShopifyの@adrianna-chang-shopify@eileencodes、そしてGitHubの@matthewdによる。アダプタライブラリのオリジナル作者はクレジット済み。

詳細
このプルリクは、activerecord-trilogy-adapterの全コードと全テストケースを移植する。Trilogyと既存のMysql2の間の重複コードはDRYにできるが、テストカバレッジを完全に確保したかったので、さしあたって全コピーし、次のプルリクでクリーンアップを提案する。
以下の変更も行われた。

  • Mysql2と同等にするため、TrilogyAdapter#explainオプションのサポートを追加
  • データベースジェネレータがアプリケーションのtrilogyオプションに対応
  • Trilogyのマイグレーション互換性を追加
  • TrilogyAdapter#select_allが更新され、MULTI_RESULTクエリ後にコネクションが正常な状態に復帰するようになった
  • Active RecordのRakefileが更新され、Trilogyに対してMySQLの抽象テストケースを実行できるようになった

追加情報

クライアント側のgithub/trilogy#64がまだマージされていない。これがリリースされたらクライアントの新バージョンをリリースしてGemfileを更新し、バージョンを合わせるべき。
同PRより


つっつきボイス:「Trilogyは、以前も話題になったGitHubによるMySQLクライアントアダプタライブラリですね(ウォッチ20220906)」「GitHubとShopifyでTrilogy導入に成功したことを受けてRailsに正式に移植したのか」

github/trilogy - GitHub
github/activerecord-trilogy-adapter - GitHub

🔗 ActiveModel::SecurePasswordのサイズバリデーションをBCrypt仕様の上限に合わせて修正

従来のバリデーションで考慮されていたのはパスワードの文字数のみであったため、BCryptによる上限72バイトを正確に反映していない可能性があった。
この変更によって、文字数のバリデーションは変えずに、文字数とバイトサイズの両方を考慮するようになる。

user = User.new(password: "a" * 73)  # 73 characters
user.valid? # => false
user.errors[:password] # => ["is too long (maximum is 72 characters)"]
user = User.new(password: "あ" * 25)  # 25 characters, 75 bytes
user.valid? # => false
user.errors[:password] # => ["is too long (maximum is 72 bytes)"]

ChatGPTGuillermo Iguaran
同Changelogより


つっつきボイス:「bcryptに72バイトの上限があったとは知らなかった」「そういえばbcryptは固定長方式でしたね」「上限を超えた場合のバリデーションエラーはたしかに必要」「現状でパスワードが72バイトを超えている人にとってはbreaking changeになるのかな」

参考: bcryptの72文字制限をSHA-512ハッシュで回避する方式の注意点 | 徳丸浩の日記
参考: bcrypt - Wikipedia

bcrypt-ruby/bcrypt-ruby - GitHub

🔗 ActiveSupport::MessagePackが追加

ActiveSupport::MessagePackシリアライザはmsgpack gemに統合され、さまざまなRubyオブジェクトをシリアライズする。ActiveSupport::MessagePackは、msgpackでサポートする基本型に加えて、TimeRangeなどの型や、ActiveSupport::TimeWithZoneActiveSupport::HashWithIndifferentAccessなどのActive Support 型もサポートしている。

ActiveSupport::MessagePackが提供する機能は、JSONMarshalと比較してパフォーマンスやメッセージサイズの削減に優れている。以下はMessageVerifierで使う場合の例。

# frozen_string_literal: true

require "benchmark/ips"
require "active_support/all"
require "active_support/message_pack"

marshal_verifier = ActiveSupport::MessageVerifier.new("secret", serializer: Marshal)
json_verifier = ActiveSupport::MessageVerifier.new("secret", serializer: JSON)
asjson_verifier = ActiveSupport::MessageVerifier.new("secret", serializer: ActiveSupport::JSON)
msgpack_verifier = ActiveSupport::MessageVerifier.new("secret", serializer: ActiveSupport::MessagePack)

ActiveSupport::Messages::Metadata.use_message_serializer_for_metadata = true
expiry = 1.year.from_now
data = { bool: true, num: 123456789, string: "x" * 50 }

Benchmark.ips do |x|
  x.report("Marshal") do
    marshal_verifier.verify(marshal_verifier.generate(data, expires_at: expiry))
  end

  x.report("JSON") do
    json_verifier.verify(json_verifier.generate(data, expires_at: expiry))
  end

  x.report("AS::JSON") do
    asjson_verifier.verify(asjson_verifier.generate(data, expires_at: expiry))
  end

  x.report("MessagePack") do
    msgpack_verifier.verify(msgpack_verifier.generate(data, expires_at: expiry))
  end

  x.compare!
end

puts "Marshal size: #{marshal_verifier.generate(data, expires_at: expiry).bytesize}"
puts "JSON size: #{json_verifier.generate(data, expires_at: expiry).bytesize}"
puts "MessagePack size: #{msgpack_verifier.generate(data, expires_at: expiry).bytesize}"
▶ベンチマーク(クリックすると表示されます)
Warming up --------------------------------------
             Marshal     1.206k i/100ms
                JSON     1.165k i/100ms
            AS::JSON   790.000  i/100ms
         MessagePack     1.798k i/100ms
Calculating -------------------------------------
             Marshal     11.748k (± 1.3%) i/s -     59.094k in   5.031071s
                JSON     11.498k (± 1.4%) i/s -     58.250k in   5.066957s
            AS::JSON      7.867k (± 2.4%) i/s -     39.500k in   5.024055s
         MessagePack     17.865k (± 0.8%) i/s -     89.900k in   5.032592s

Comparison:
         MessagePack:    17864.9 i/s
             Marshal:    11747.8 i/s - 1.52x  (± 0.00) slower
                JSON:    11498.4 i/s - 1.55x  (± 0.00) slower
            AS::JSON:     7866.9 i/s - 2.27x  (± 0.00) slower

Marshal size: 254
JSON size: 234
MessagePack size: 194

さらに、ActiveSupport::MessagePack::CacheSerializerActiveSupport::Cacheのコーダーに適したシリアライザーである。ActiveSupport::MessagePack::CacheSerializerは、読み込み済みの関連付けを含むActiveRecord::Baseインスタンスをシリアライズ可能で、ActiveSupport::MessagePackと同様に、パフォーマンスの向上とペイロードサイズの削減を実現できる。

# frozen_string_literal: true

require "benchmark/ips"
require "active_support/message_pack"

ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")

ActiveRecord::Schema.define do
  create_table :posts, force: true do |t|
    t.string :body
    t.timestamps
  end

  create_table :comments, force: true do |t|
    t.integer :post_id
    t.string :body
    t.timestamps
  end
end

class Post < ActiveRecord::Base
  has_many :comments
end

class Comment < ActiveRecord::Base
  belongs_to :post
end

post = Post.create!(body: "x" * 100)
2.times { post.comments.create!(body: "x" * 100) }
post.comments.load
cache_entry = ActiveSupport::Cache::Entry.new(post)

Rails70Coder = ActiveSupport::Cache::Coders::Rails70Coder
CacheSerializer = ActiveSupport::MessagePack::CacheSerializer

Benchmark.ips do |x|
  x.report("Rails70Coder") do
    Rails70Coder.load(Rails70Coder.dump(cache_entry))
  end

  x.report("CacheSerializer") do
    CacheSerializer.load(CacheSerializer.dump(cache_entry))
  end

  x.compare!
end

puts "Rails70Coder size: #{Rails70Coder.dump(cache_entry).bytesize}"
puts "CacheSerializer size: #{CacheSerializer.dump(cache_entry).bytesize}"
▶ベンチマーク(クリックすると表示されます)
Warming up --------------------------------------
        Rails70Coder   329.000  i/100ms
     CacheSerializer   492.000  i/100ms
Calculating -------------------------------------
        Rails70Coder      3.285k (± 1.7%) i/s -     16.450k in   5.008447s
     CacheSerializer      4.895k (± 2.4%) i/s -     24.600k in   5.028803s

Comparison:
     CacheSerializer:     4894.7 i/s
        Rails70Coder:     3285.4 i/s - 1.49x  slower

Rails70Coder size: 808
CacheSerializer size: 593

/cc @byroot: あなたがmsgpackShopify/paquitoで多くの作業を行ってきたことを認識している。このプルリクはpaquitoに強くインスパイアされているので、共著に加えておいた。このコードをpaquitoで役立てる(もしくはmsgpackにアップストリームする)ためにこちらで何かできることはあるだろうか?
同PRより


つっつきボイス:「お、ついにMessagePackがRailsにやってきた🎉」

msgpack/msgpack-ruby - GitHub

「MessagePackって何でしょうか?」「MessagePackは古くからAPI通信のプロトコルなどでペイロードとして使われるフォーマットの1つですね: 既にRailsでもシリアライザとして使っている人は結構いるんじゃないかな」

「たしかにMessagePackサイトを見るとものすごくたくさんの言語やライブラリに対応していますね」「そうそう、特定の言語に依存しないフォーマットです: 言語がJSONに対応するとJSONパーサーなどが必要になるのでコードベースが大きくなりがちなんですが、MessagePackはそのあたりがシンプルになっていたという覚えがあります」「JSONはテキストフォーマットだけどMessagePackはバイナリフォーマットで、その分コンパクトなんですね」「MessagePackは読んだそばから解析できるのもいい点です」

🔗 PostgreSQL: UNIQUE制約でUSING INDEXをサポート

動機/背景
#46192の続き。

詳細
UNIQUE制約(一意制約)の定義で既存のインデックスを利用する:using_index オプションを追加した。:using_indexオプションを使うと、指定されたUNIQUEインデックスがUNIQUE制約に変更される。

add_unique_key :users, deferrable: :immediate, using_index: 'unique_index_name'

UNIQUE制約の内部ではUNIQUEインデックスを構築する。
UNIQUEインデックスが既に作成済みであれば、制約を生成するときにUNIQUEインデックスの作成が不要になるので、UNIQUE制約の構築がかなり高速化される。

先延ばし不可の(non-deferrable)UNIQUEインデックスは、先延ばし可能な(deferrable)UNIQUE制約に変更可能。
同PRより


つっつきボイス:「PostgreSQLのUSING INDEXで既存のUNIQUEインデックスをUNIQUE制約に変更できるようになったそうです」「deferrableといえば、以前PostgreSQLのDEFERRABLEが使えるようになったという話がありましたね(ウォッチ20211011): 今回の改修によって、deferrableでないUNIQUEインデックスを後付けでdeferrableにできるようになったんですね、なるほど」

参考: PostgreSQL 14.5ドキュメント CREATE TABLE

DEFERRABLE
NOT DEFERRABLE
制約を遅延させることが可能かどうかを制御します。 遅延不可の制約は各コマンドの後すぐに検査されます。 遅延可能な制約の検査は、(SET CONSTRAINTSコマンドを使用して)トランザクションの終了時まで遅延させることができます。 NOT DEFERRABLEがデフォルトです。 現在、UNIQUEPRIMARY KEYEXCLUDEREFERENCES(外部キー)制約のみがこの句を受け付けることができます。 NOT NULLおよび CHECK制約は遅延させることができません。 遅延可能な制約はON CONFLICT DO UPDATE句を含むINSERT文において、競合解決のために使うことはできないことに注意してください。
CREATE TABLEより

🔗 fixture読み込み時の外部キーエラーの理由を表示するようになった

#42674でfixture作成時Railsが外部キーを検証する機能が追加された。その後、どの外部キーで違反が発生したかも表示されたら助かるというフィードバックをもらった(これまでの修正の試みについては#44943#47780を参照)。

このプルリクは、それらのプルリクでのアイデアのいくつかを統合可能にする。

  • all_foreign_keys_valid?を非推奨にし、今後はcheck_all_foreign_keys_valid!を使う。
  • PostgreSQLとSQLiteのアダプタでraiseするときに、外部キーエラーを詳しく表示する。
  • 他のプルリクの作者を共著者にしてクレジットする。
  • 新しい非推奨化APIで動作するよう、非推奨化処理を更新する。
  • テストを更新する。

今後エラーメッセージは以下のように表示される。
PostgreSQL:

Foreign key violations found in your fixture data. Ensure you aren't referring to labels that don't exist on associations. Error from database:

PG::ForeignKeyViolation: ERROR:  insert or update on table "fk_pointing_to_non_existent_objects" violates foreign key constraint "fk_that_will_be_broken"
DETAIL:  Key (fk_object_to_point_to_id)=(980190962) is not present in table "fk_object_to_point_tos".
CONTEXT:  SQL statement "UPDATE pg_constraint SET convalidated=false WHERE conname = 'fk_that_will_be_broken' AND connamespace::regnamespace = 'public'::regnamespace; ALTER TABLE public.fk_pointing_to_non_existent_objects VALIDATE CONSTRAINT fk_that_will_be_broken;"
PL/pgSQL function inline_code_block line 16 at EXECUTE

SQLite:

Foreign key violations found in your fixture data. Ensure you aren't referring to labels that don't exist on associations. Error from database:

Foreign key violations found: fk_pointing_to_non_existent_objects

クローズ: #47780#44943

cc @s-mage@danini-the-panini
同PRより


つっつきボイス:「これは嬉しい機能👍」「fixture読み込みのエラーを何でもActiveRecord::StatementInvalidにせずに詳しい情報を出してくれるの助かります😂」

# activerecord/lib/active_record/connection_adapters/abstract_adapter.rb#L637
      # Override to check all foreign key constraints in a database.
      def all_foreign_keys_valid?
+       check_all_foreign_keys_valid!
        true
+     rescue ActiveRecord::StatementInvalid
+       false
+     end
+     deprecate :all_foreign_keys_valid?, deprecator: ActiveRecord.deprecator

Rails 7 API: ActiveRecord::FixtureSet(翻訳)

🔗 ActiveSupport::Inflector#underscoreで正規表現のキャプチャを削減

動機/背景
このプルリクは小さな改善のために作成した。

詳細
このプルリクでは、ActiveSupport::Inflector#underscoregsub!でキャプチャを行わないようにしている。
これによって、$1/$2による短い文字列の作成とアンダースコア追加をスキップし、置き換え対象文字列から除外する。
同PRより

# activesupport/lib/active_support/inflector/methods.rb#L97
    def underscore(camel_cased_word)
      return camel_cased_word.to_s.dup unless /[A-Z-]|::/.match?(camel_cased_word)
      word = camel_cased_word.to_s.gsub("::", "/")
      word.gsub!(inflections.acronyms_underscore_regex) { "#{$1 && '_' }#{$2.downcase}" }
-     word.gsub!(/([A-Z])(?=[A-Z][a-z])|([a-z\d])(?=[A-Z])/) { ($1 || $2) << "_" }
+     word.gsub!(/(?<=[A-Z])(?=[A-Z][a-z])|(?<=[a-z\d])(?=[A-Z])/, "_")
      word.tr!("-", "_")
      word.downcase!
      word
    end

つっつきボイス:「パッチモンスターことnobuさんによる改修です」「正規表現の()で余分なキャプチャが発生するのを減らした、なるほど」「使わないキャプチャがあるとメモリを余分に食いますよね」

参考: Rails API underscore -- ActiveSupport::Inflector

参考: Rubyist Hotlinks 【第 9 回】 中田伸悦さん

なお、Rubyの正規表現でキャプチャはしないけどやむを得ず(式)を使いたい場合は、(?:式)のように書くことでキャプチャされなくなります。なお、先読みや後読みはキャプチャされません。

はじめての正規表現とベストプラクティス#4 先読みと後読みを極める

🔗 ドキュメント: アセットパイプラインガイドを更新


つっつきボイス:「既に日本語版Railsガイドにも反映されています↓が、Rails公式情報でも紹介されました」「Rails 7.0に合わせてかなりがっつりリライトされている」「アセットパイプラインガイドの原文更新には自分も関わったんですが、その中でSprocketsのガイドを分けようかという構想も持ち上がっていました(#47012コメント)」「Sprocketsのガイドはある方がいいですね」

参考: アセットパイプライン - Railsガイド
参考: 📕 アセットパイプラインガイドを大幅更新|YassLab 株式会社|note

🔗Rails

🔗 スライド『Rails 7.1をn倍速くした話』


つっつきボイス:「amatsudaさんのこのスライドをついさっきツイートで見かけたので早速取り上げました」「Railsのedgeブランチにamatsudaさんによる最適化がいろいろ入っていたのはこれまでも見かけていましたが、スライドにまとめてくれたんですね」「対象を絞り込みながら最適化を進める手法の解説めっちゃ面白い」「ヤン提督って誰かと思ったら銀英伝なんですね」

参考: 銀河英雄伝説 - Wikipedia

「このあたりの改修↓はamatsudaさんのコミットで見た覚えがあります(ウォッチ20221220)」「そうそう、Arrayオブジェクトの生成を避けるための改修ですね」

「スライドにもあるように、この種の最適化はライブラリやミドルウェア向けのものなので、アプリケーションコードでは、データ処理・解析系などでよほどパフォーマンス重視の実装を求められるのでない限りやるべきではないでしょうね」

「edgeにこんなにパッチを当ててくれた↓」「すごい」「今回はAction Controller編で、次回はAction View & Active Record編か」「Rails 7.1の高速化、期待できそう」

後でamatsudaさんのedgeのコミットリストを見つけました↓。

参考: Rails Contributors - #20 Akira Matsuda - Edge -- 92件

🔗Ruby

🔗 Rubyの*args**kwargs...によるdelegationが遅い問題


つっつきボイス:「上のスライドで取り上げられていたissue #19165です」「パラメータなしの*args**kwargsでこんなことが起きていたとは」「この問題を見つけたのすごい」「ko1さんが早くも改善に取り組み始めていますね(現在ドラフト)」


今週は以上です。

バックナンバー(2023年度第2四半期)

週刊Railsウォッチ: 第1回Rails Worldが10月に開催、『研鑽Rubyプログラミング』でRuby本体も高速化ほか(20230427後編)

ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。

Rails公式ニュース


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。