- Ruby / Rails関連
週刊Railsウォッチ: Hotwireの用途解説記事、RubyKaigi 2022プロポーザル募集開始ほか(20220523前編)
こんにちは、hachi8833です。RubyKaigi 2022のプロポーザルフォームが公開されました。
Call for RubyKaigi 2022 Proposals is now open! 🥷💨 https://t.co/mLjIuqTvAM #rubykaigi
— RubyKaigi (@rubykaigi) May 17, 2022
🔗Rails: 先週の改修(Rails公式ニュースより)
今回は、以下の更新情報の中からまだ取り上げていなかったものを中心に見繕いました。
- 公式更新情報: Ruby on Rails — More async queries, pattern matching and no more autoclosed PRs!
- コミット差分: Comparing @{2022-05-12}...main@{2022-05-19} · 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_screenshot
-- ActionDispatch::SystemTesting::TestHelpers::ScreenshotHelper
🔗 バリデーションで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
↓でこの設定が効くようになったんですね」
「大量の削除を一気に実行するときにアクシデントが起きたりするの、あるある」「こういう関連付け削除のエラーハンドリングってどうしたらいいんでしょう?」「エラーレポートサービスで収集するぐらいしかないかな...」
「テストを見ると、バッチサイズを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の用途解説記事
「Hotwireの良かった点、辛かった点、向いているケース、向いていないケース」という記事を書きました〜。
Rails受託歴が長めなので、Hotwireは受託にピッタリ、という話が多めになっています。
至らない点も多いと思いますが、よろしくおねがいします〜。https://t.co/WP6wZbI5ga— shita (@shita1112) May 16, 2022
つっつきボイス:「先週紹介したこちらの記事↓と同じ著者です(ウォッチ20220516)」「今度の記事も評判いいですね: 実際にHotwireを使った人の記事は貴重👍」
「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
🔗 searchjoy: 検索クエリ分析gem(Ruby Weeklyより)
- デモサイト: Searchjoy
つっつきボイス:「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が使ってみた記事なので拾ってみました」
「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のセキュリティ修正がリリースされていましたね↓」「ダブルフリー(メモリの二重解放)は結構重大」
🔗 SoE/SoR比
ウェブサービスのフロントエンドとバックエンド比重について考えてたときにこの記事を読んで「SoE/SoR比」でウェブサービスを分類できるのではないかとふと思った。そしてフロントエンドの発展により、その比率次第でサービス毎の最適解が劇的に異なるのではないかと。https://t.co/PCBndXce5k
— masa寿司 (@masa_iwasaki) May 18, 2022
つっつきボイス:「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後編)
- 20220516前編 Active Modelで属性のパターンマッチをサポート、猫でもわかるHotwire入門ほか
- 20220511後編 Ruby 3.2.0devにRust版YJITがマージ、Docker Compose V2ほか
- 20220510前編 Active RecordにPromiseと非同期集計メソッドがマージ、climate_control gemほか
- 20220419後編 RubyのGCコンパクション改修、jemalloc、ReDoSの自動検出修正ほか
- 20220418前編 RailsConf 2022が5月17〜19日開催、認可機能解説記事ほか
- 20220412後編 HashieでRubyのハッシュを強化、最近のRubyコア解説記事ほ
- 20220411前編 Turbo Railsチュートリアル、Active Recordの「Leaky Abstraction」を削減ほか
- 20220406後編 RBS関連記事、Ruby formatterプロジェクト、Google Cloud Runほか
- 20220404前編 Ruby 3.2.0 Preview 1リリース、Rails向けDocker環境ジェネレータ、scientist gemほか
今週の主なニュースソース
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。
週刊Railsウォッチについて
TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)