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

週刊Railsウォッチ: Hotwireの用途解説記事、RubyKaigi 2022プロポーザル募集開始ほか(20220523前編)

こんにちは、hachi8833です。RubyKaigi 2022のプロポーザルフォームが公開されました。

週刊Railsウォッチについて

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

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

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

今回は、以下の更新情報の中からまだ取り上げていなかったものを中心に見繕いました。

🔗 システムテストのスクリーンショットヘルパーにhtml:screenshotキーワード引数が追加

これは#36545で追加された環境変数の上に構築されている。
テストコードでhtmlやスクリーンショットをリクエストできるようになると、テストを実行するたびにスクリーンショットやHTMLをダンプする代わりに、スクリーンショットごとに選択的にダンプできるようになるので良い。

# スクリーンショットを撮影してiTermで表示し、HTMLをファイルにダンプして、両者のパスを出力
take_screenshot(html: true, screenshot: "inline")
# HTMLをファイルにダンプしてパスを出力
take_screenshot(html: true)
# スクリーンショットを撮影してiTermで表示し、パスを出力
take_screenshot(screenshot: "artifact")
# スクリーンショットを撮影してパスを出力
take_screenshot # takes a screenshot, prints its path

同PRより


つっつきボイス:「take_screenshotメソッドって使ったことないんですが、これでテスト中のブラウザ画像を保存できるんですか?」「ヘッドレスブラウザでシステムテストを実行するとできたはず: 重くなるので多用は避けたいですが、画面のスクショにバージョンを付けて差分を調べられると思います」「なるほど」「HTMLの差分も取れるようになるのはいい👍」

参考: Rails API take_screenshotActionDispatch::SystemTesting::TestHelpers::ScreenshotHelper

2020年のRailsでブラウザテストを「正しく」行う方法(翻訳)

🔗 バリデーションでlambdaをrecord引数なしで渡せるように修正

  • バリデーションでlambdaをrecord引数なしで渡せるようにする
# 改修前
validates_comparison_of :birth_date, less_than_or_equal_to: ->(_record) { Date.today }
# 改修後
validates_comparison_of :birth_date, less_than_or_equal_to: -> { Date.today }

fatkodima
同Changelogより


つっつきボイス:「なるほど、バリデータに上の(_record)のような引数を渡さなくても済むようになった👍」「使わない引数なら渡さなくてもいいですよね」「割と修正多いかも」

🔗 関連付けの非同期削除でバッチサイズを設定可能になった

このプルリクにより、アプリケーションが関連付けのdependent: :destroy_asyncオプションで1件のバックグラウンドジョブで削除されるレコードの最大数を指定可能になる。
デフォルトでは現在の動作と同じ。親レコードが削除されると、すべての従属レコードが単一バックグランドジョブで削除される。
従属レコード数がこの設定を超えると、レコードが複数のバックグラウンドジョブで破棄される。

GitHubでは、関連付けられているレコードをバックグラウンドで削除するカスタムメソッドを使っており、これをdependent: :destroy_asyncに置き換えたいと思う。
関連付けの中には従属レコード数が膨大なものがあり、自社インフラでバックグラウンドジョブを速やかに完了させる必要がある。そこで、1件のバックグラウンドジョブで削除される従属レコードの最大上限数を設定し、レコード数がこの制限を超えたら追加ジョブをキューに入れるようにする。
同PRより


つっつきボイス:「active_record.destroy_association_async_batch_sizeで関連付けの削除にバッチサイズの上限を指定して、それを超えたら複数ジョブで削除できるようになった」「以前入ったdependent: :destroy_async↓でこの設定が効くようになったんですね」

Rails 6.1: 関連付けをバックグラウンド削除する「dependent: :destroy_async」(翻訳)

「大量の削除を一気に実行するときにアクシデントが起きたりするの、あるある」「こういう関連付け削除のエラーハンドリングってどうしたらいいんでしょう?」「エラーレポートサービスで収集するぐらいしかないかな…」

「テストを見ると、バッチサイズを1にしておいてレコードを2つ追加してからbook.destroyしたときにジョブが2つできることを確かめている感じかな↓」「assert_enqueued_withをネストさせてbook.destroyを実行してるのか」

# activerecord/test/activejob/destroy_association_async_test.rb
  test "enqueues multiple jobs if count of dependent records to destroy is greater than batch size" do
    ActiveRecord::Base.destroy_association_async_batch_size = 1

    tag = Tag.create!(name: "Der be treasure")
    tag2 = Tag.create!(name: "Der be rum")
    book = BookDestroyAsync.create!
    book.tags << [tag, tag2]
    book.save!

    job_1_args = ->(job_args) { job_args.first[:association_ids] == [tag.id] }
    job_2_args = ->(job_args) { job_args.first[:association_ids] == [tag2.id] }

    assert_enqueued_with(job: ActiveRecord::DestroyAssociationAsyncJob, args: job_1_args) do
      assert_enqueued_with(job: ActiveRecord::DestroyAssociationAsyncJob, args: job_2_args) do
        book.destroy
      end
    end

    assert_difference -> { Tag.count }, -2 do
      perform_enqueued_jobs only: ActiveRecord::DestroyAssociationAsyncJob
    end
  ensure
    Tag.delete_all
    BookDestroyAsync.delete_all
    ActiveRecord::Base.destroy_association_async_batch_size = nil
  end

🔗 rails newジェネレータに--nameオプションが追加

このプルリクでは、rails newで作成する新しいアプリの名前を設定するオプションを追加する。
--nameオプションを指定すると、フォルダ名と異なる名前でアプリケーション名をオーバーライドする。

rails new my-app-folder --name=my-actual-app-name

上のコマンドは新規Railsアプリをmy-app-folderフォルダ内に生成するが、config/application.rbの構造は以下のようになる。

module MyActualAppName
  class Application < Rails::Application
  end
end

このオプションは、以下のようにカレントフォルダ内でRailsアプリケーションを生成するときに最も重宝する。

rails new . --name=my-app

同PRより


つっつきボイス:「rails newの改修ですね」「アプリケーションのフォルダ名とは別にモジュールのアプリ名を指定したいときに使うのね」「使う場面はあまりなさそうな気もするけど、あっていい機能👍」

🔗 番外: Railsリポジトリのプルリク自動クローズ廃止と、Rails issuesチーム新設案

レビュアーに「stale」メッセージを送信し、期間内にレビューされなかったプルリクを閉じる形でプルリクリストを片付けるというアイデアは、メンテナーにとっては有効でも、実際にはコントリビュータによる投稿を促進しなくなる。
プルリクを開いたまま何の応答もしないのもコントリビュータのモチベーションを下げるので、botのこの機能を無効にするが、プルリク数を抑えつつも、プルリクを無視したり「stale」で却下したり自動で閉じたりするのではなく、コントリビュータが既に行った作業を称えるプロセスを考え出す必要がある。
同コミットより


つっつきボイス:「お、プルリクの自動クローズをやめるのか」「修正そのものはGitHubのstale.yml設定変更のみですね」

「おそらくそれに関連して、Railsにissuesチームを新設するプルリクがオープンされていました↓」「お、community.ymlにメンバーが追加されていますね」

参考: Add information about the issues team by rafaelfranca · Pull Request #37 · rails/website — 現在オープン

「プルリク自動クローズ廃止に伴うフロー変更の一環として、issuesチーム新設も進めている感じでしょうか?」「両者の関係について明言はされていないけど、そう思ってよさそうですね👍」

🔗Rails

🔗 Hotwireの用途解説記事


つっつきボイス:「先週紹介したこちらの記事↓と同じ著者です(ウォッチ20220516)」「今度の記事も評判いいですね: 実際にHotwireを使った人の記事は貴重👍」

参考: 猫でもわかるHotwire入門 Turbo編

「Hotwireについては、自分たち請負側がUI設計も含めて開発できる案件なら選択肢としてよさそうかなと個人的に思っています: 逆にUI設計を請負側で自由にできない案件だとちょっと厳しいかも」「たしかに」「記事で言う『Hotwireは受託開発に向いている』というのは主に前者のことを指しているんだろうなと思いました」


「ところで、記事にもHerokuでHotwireが使いづらいとある、たしかに」「私も上の記事でHerokuがHTTP/2にまだ対応していない↓ことを思い出しました」「え、そうなんですか」「オレオレRailsアプリをRails 7にアップグレードしたときにimportmap-railsを導入したんですが、HerokuがHTTP/2に対応していないのでリクエストのTCPコネクションが以前より増えていると思うとちょっと悲しい😢」

参考: Does Heroku have plans to support HTTP/2? – Heroku Help
参考: HTTP/2とは – JPNIC

Rails 7: importmap-rails gem README(翻訳)

🔗 searchjoy: 検索クエリ分析gem(Ruby Weeklyより)

ankane/searchjoy - GitHub


つっつきボイス:「ankaneさんがまた新しいgemを作ったんですね」「Railsアプリの検索クエリやコンバージョンをトラッキングして管理画面などに表示できるgemらしい」「検索の分析ですか」「Elasticsearch、Sphinx、Solrというメジャーなものも含めて任意の検索プラットフォームをサポートしているのね」

# 同リポジトリより
Searchjoy::Search.create(
  search_type: "Item", # typically the model name
  query: "apple",
  results_count: 12,
  user_id: 1
)

参考: 無料かつオープンな検索:開発元が提供するElasticsearch、ELK、Kibana | Elastic
参考: 検索アダプタ — Sphinx documentation
参考: Apache Solr – Wikipedia

「同じようなことはGoogleアナリティクスに結果を投げて調べることもできそうですが、Googleアナリティクス備え付けの分析ツールだと自由に調べにくい場合もあるでしょうね: searchjoyは自分たちのデータベースに結果を保存できるので、検索クエリをより詳しく調べたいときに使う感じかな」「なるほど」「知っていれば使いたくなるかも: ただこの種のデータは大きくなりがちなので、そこは注意が必要そう」

🔗 scientist gemでRailsコードをリファクタリングする


つっつきボイス:「scientist gemはこれまでもウォッチで何度か取り上げましたが(ウォッチ0220404)、AppSignalが使ってみた記事なので拾ってみました」

github/scientist - GitHub

「scientist gemは、あるメソッドの内部実装を変更した際に、before/after両方のコードを裏で動かすことで前後に差違がなかったかどうかをproduction loadで調べられる: たしかにリファクタリングに向いていそう」「歴史の長いRailsアプリに良さそうですね」

# 同記事より
--------------------------------------------------------------------------------
Experiment: prime-factors
--------------------------------------------------------------------------------
Earliest results: 2022-04-27T02:42:45Z
Latest result:    2022-05-01T17:27:39Z (5 days)

3 of 4 (75.00%) correct
1 of 4 (25.00%) mismatched

Median time delta: +0.000s  (90% of observations between +0.000s and +0.000s)

Speedups (by percentiles):
      0%  [                         ·         █               ]    +2.4x faster
      5%  [                         ·         █               ]    +2.4x faster
     10%  [                         ·         █               ]    +2.4x faster
     15%  [                         ·         █               ]    +2.4x faster
     20%  [                         ·         █               ]    +2.4x faster
     25%  [                         ·         █               ]    +2.4x faster
     30%  [                         ·         █               ]    +2.4x faster
     35%  [                         ·         █               ]    +2.4x faster
     40%  [                         ·         █               ]    +2.4x faster
     45%  [                         ·         █               ]    +2.4x faster
     50%  [ · · · · · · · · · · · · · · · · · █ · · · · · · · ]    +2.4x faster
     55%  [                         ·         █               ]    +2.4x faster
     60%  [                         ·         █               ]    +2.4x faster
     65%  [                         ·         █               ]    +2.4x faster
     70%  [                         ·                        █]    +6.9x faster
     75%  [                         ·                        █]    +6.9x faster
     80%  [                         ·                        █]    +6.9x faster
     85%  [                         ·                        █]    +6.9x faster
     90%  [                         ·                        █]    +6.9x faster
     95%  [                         ·                        █]    +6.9x faster
    100%  [                         ·                        █]    +6.9x faster
--------------------------------------------------------------------------------

🔗 Rack::Sendfile


つっつきボイス:「つっつきの直前に公開されたセキュリティ関連記事です」「RailsのRack::Sendfileの問題と、RubyのRegexp脆弱性の問題か」

「前者のRack::Sendfileは、記事にもあるようにHTTP_X_ACCEL_MAPPINGなどを使わなければたいてい不要だったと思います」「リクエストヘッダーを細工してRegex injectionを引き起こす話は前も見た気がする」「Rack::Sendfileを削除するとbreaking changesになるのでまだ削除されていないんですね↓」

参考: Remove Rack::SendFile from default middleware. · Issue #41148 · rails/rails — 現在オープン
参考: Remove Rack::Sendfile from the default middleware stack by SValkanov · Pull Request #44556 · rails/rails — 現在オープン

「後者はこの間Rubyのセキュリティ修正がリリースされていましたね↓」「ダブルフリー(メモリの二重解放)は結構重大」

Ruby 3.1.2/3.0.4/2.7.6/2.6.10セキュリティ修正がリリースされました

🔗 SoE/SoR比

つっつきボイス:「SoE/SoR比は、特にエンジニアを募集するときの基準としても有用ですね」「System of EngagementとSystem of Recordの略というのを初めて知りました」「最初SoEという言葉が流行して、後から対義語として従来のサーバーサイドやデータベース中心のシステムがSoRと名付けられた感じです」

「SoEとSoRは、それぞれ大まかにフロントエンドとバックエンドを指している感じで合ってますか?」「方向性はそんな感じですが、SoEは最近で言うDXと同様にユーザー操作を重視する路線なので、結果的にフロントエンド重視の設計になります」「なるほど」「SoRは対照的にRDBがメインになる」

参考: デジタルトランスフォーメーション(DX) – Wikipedia

「記事で『RailsはSoRに適したフレームワーク』とあるのは自分ももっともだと思います」「そうですね」「要件に対して、(Railsにするかどうかも含めて)どんな技術を選定するかを考えるときに納得感がある記事👍」


「技術の選定は組織の編成などによっても変わってくるので、SoE/SoR比のようなものは意識しておく必要があると思います」「アプリが成長したときもSoE/SoR比が変わりそうですね」「アプリが成功して利用者が増えれば要件がSoE寄りにシフトするのが普通ですね: 逆に社内システムのようなものはSoR寄りになる」

「アプリのユーザーに近い部分はSoEで、バックエンドはSoRでアプローチするのが、最近の開発スタイルでは主流でしょうね」「SoEだけではないということですね」

「少し前にSoEがブームになった頃、SoRはやがて滅びるみたいに言われていたこともありましたが、結局の所SoRは滅びず、Railsも生き残りました: これは本質的にビジネスアプリが扱いたいデータは管理者視点ではSoR的であることが多く、SoEは重要だけどSoRが適した領域もあるので、両者のバランスが大事だよね、という話なんだろうなと思います」

「Railsが流行り始めた頃のようなB2Cアプリのrapid prototyping的なユースケースは今ではフロントエンド技術の方が隆盛ですが、そうしたユースケースでも、既にあるRDBのデータを検索・集計して扱う用途などでは今でもRailsがやりやすいシーンはあるでしょうね」


前編は以上です。

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

週刊Railsウォッチ: rubygemsに「scoped gems」の提案、RSpecのブロック構文ほか(20220517後編)

今週の主なニュースソース

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

Rails公式ニュース

Ruby Weekly


CONTACT

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