- Ruby / Rails関連
週刊Railsウォッチ: Kaigi on Rails 2022のタイムテーブル発表、書籍『Practicing Rails』ほか(20221003前編)
こんにちは、hachi8833です。
🔗Rails: 先週の改修(Rails公式ニュースより)
- 公式更新情報: Ruby on Rails — Rack 3 and Rails 7.0.4, 6.1.7, and 6.0.6 releases, ActionDispatch::Cookies, etc
🔗 コネクションハンドラメソッドのバグを修正
active_connections?
、clear_active_connections!
、clear_reloadable_connections!
、clear_all_connections!
、flush_idle_connections!
がデフォルトですべてのプールで動作するようになった。従来は指定がないとデフォルトでcurrent_role
または:writing
ロールを使っていた。
Eileen M. Uchitelle
同Changelogより
以前自分がRailsでマルチプルデータベースのロールを実装したときはハンドラーが2つあったので、
active_connections?
、clear_active_connections!
、clear_reloadable_connections!
、clear_all_connections!
、flush_idle_connections!
というメソッドが現在の(あるいは渡された)ロールのみで動作し、(ロールにかかわらず)対象がすべてのプールではなかったのは理にかなっていた。これを削除して、すべてのプールをプールマネージャが管理するハンドラに移動したときは、元の振る舞いが変わらないようこれらのメソッドをそのままにしておいた。これらのメソッドはアプリケーションからしか呼ばれず、Railsからは呼び出されないので、そのときはこれでよいと思えた。しかし昨日、これらのメソッド(
flush_idle_connections!
、clear_active_connections!
、clear_reloadable_connections!
)の一部が起動時にActive Record railtieからすべて呼び出されていることに気づいた。残念ながら、これではマルチプルデータベースのRailsアプリケーションを起動したときに、書き込みを除くすべてのコネクションがflushもクリアもされないということになる。
ここでの変更では、読み込みロールなどが直接渡された場合は既存の振る舞いを維持し、それ以外の場合、ロールが
nil
(新しいデフォルト値)ならすべてのコネクションをフォールバックして非推奨警告を出力する。今後はこれがデフォルトの振る舞いとなる。この非推奨警告を手軽にオフにできるようにするため、:all
引数(警告を出力せずにすべてのプールを使う)を追加しておいた。この非推奨警告は、プールマネージャに複数のロールがある場合にのみ出力され、それ以外の場合は従来の振る舞いを前提とする。このバグが影響するのはロールが複数あるアプリケーションだけであり、上述のメソッドが
connected_to
コンテキストの外で呼び出された場合にのみ発生する。これらのメソッドは今後current_role
のセットを考慮しなくなるので、これらのメソッドをアプリケーションのすべてのプールで動作させたくない場合は、(ロールを)明示的に指定する必要がある。cc/ @matthewd(今朝相談させてもらった)
同PRより
つっつきボイス:「比較的エッジケースのバグかな」「マルチプルデータベースコネクション関連のバグがまだ残っていたんですね」「マルチプルデータベースを使っているプロジェクトは多くないと思いますが、使っているところはだいたい複雑になっていてその分エッジケースのバグを踏みやすいかもしれませんね」
参考: Active Record で複数のデータベース利用 - Railsガイド
🔗 ActionViewレンダリングのinstrumentationが返すデータに:locals
も出力可能になった
改修前:
{
identifier: "/Users/adam/projects/notifications/app/views/posts/index.html.erb",
layout: "layouts/application"
}
改修後:
{
identifier: "/Users/adam/projects/notifications/app/views/posts/index.html.erb",
layout: "layouts/application",
locals: {foo: "bar"}
}
Aaron Gough
同Changelogより
つっつきボイス:「ActionViewのレンダラーのinstrumentationで:locals
の内容も出力できるようになったんですね: locals
には個人情報のようなセンシティブな情報が含まれる可能性もあるので出力する場合は注意が必要だと思いますが、取れる情報が増えるのはありがたい👍」
参考: § 3.3 Action View -- Active Support の Instrumentation 機能 - Railsガイド
🔗 run_callbacks
メソッドにbefore/around/afterコールバックのいずれかだけを実行するオプションを追加
概要
現在のrun_callbacks
メソッドでは、あるグループのすべてのコールバック(すべての保存、作成、削除など)の実行を強制され、before/around/afterコールバックのいずれかだけを指定できなかった。
このプルリクは、ユーザーが実行したいコールバック種別を指定するオプションパラメータを受け取れるようrun_callbacks
を変更することで、この機能を追加するためのもの。
その他の情報
このパラメータを指定しない場合、run_callbacks
の振る舞いは従来と完全に同じになるべき。
つっつきボイス:「run_callbacks
の第2引数で:before
や:after
や:around
という種別を指定できるようになった」「aroundは、beforeとafterを両方実行するということですね」「コールバックのaroundはネストも含めて正しい順序で実行されることが重要」「そういえば正規表現のドキュメントでlookahead(先読み)とlookbehind(後読み)の両方を指すときにlookaroundと呼んでいたのを思い出しました」
# activesupport/test/callbacks_test.rb#1237
class RunSpecificCallbackTest < ActiveSupport::TestCase
def test_run_callbacks_only_before
klass = AllSaveCallbacks.new
klass.run_callbacks :save, :before
assert_equal ["before_save_1", "before_save_2"], klass.history
end
def test_run_callbacks_only_around
klass = AllSaveCallbacks.new
klass.run_callbacks :save, :around
assert_equal [
"around_save_1_before",
"around_save_2_before",
"around_save_2_after",
"around_save_1_after"
],
klass.history
end
def test_run_callbacks_only_after
klass = AllSaveCallbacks.new
klass.run_callbacks :save, :after
assert_equal ["after_save_2", "after_save_1"], klass.history
end
end
参考: §1.2 Callbacksモジュール -- Active Model の基礎 - Railsガイド
参考: Rails API run_callbacks
-- ActiveSupport::Callbacks
🔗 ActionDispatch::Cookies
のJSONデシリアライザのエラーをrescue
するよう修正
この変更を行わないと、
action_dispatch.cookies_serializer
が:json
に設定されているアプリが:marshal
シリアライズドcookieを読み取ろうとしてエラーが発生したときにcookieがクリアされず、アプリのユーザーがブラウザのcookieを手動でクリアしなければならなくなる。
(元のバグに関する議論は#45127を参照)
Nathan Bardoux
同Changelogより
つっつきボイス:「cookieのjsonデシリアライズでJSON::ParserError
エラーがrescue
対象に含まれていなかったためにmarshal dumpが残っていたのか↓」「なるほど」「Javaだとthrows
を書けるのでこういうrescue
漏れは発生しないんですけどね」
# actionpack/lib/action_dispatch/middleware/cookies.rb#L675
private
def parse(name, encrypted_message, purpose: nil)
deserialize(name) do |rotate|
@encryptor.decrypt_and_verify(encrypted_message, on_rotation: rotate, purpose: purpose)
end
- rescue ActiveSupport::MessageEncryptor::InvalidMessage, ActiveSupport::MessageVerifier::InvalidSignature
+ rescue ActiveSupport::MessageEncryptor::InvalidMessage, ActiveSupport::MessageVerifier::InvalidSignature, JSON::ParserError
nil
end
参考: module Marshal
(Ruby 3.1 リファレンスマニュアル)
🔗Rails
🔗 Kaigi on Rails 2022のタイムテーブルが公開
皆さん、大変お待たせいたしました。
10/21(金)・22(土)開催
Kaigi on Rails 2022 タイムテーブルを公開しました🎉https://t.co/qAWAiiQ3AX
事前に気になるトークを要チェックです!無料参加登録はこちらから↓https://t.co/cInlgqV0E8#kaigionrails
— Kaigi on Rails (@kaigionrails) September 28, 2022
つっつきボイス:「ついにタイムテーブルが発表された🎉」「10/21(金)〜10/22(土)のそれぞれ12時から開始で、リモート開催のみか」「スロットはどちらも1つだけなのでどれを見るか悩まずに済みそう」「その分発表数もDay1が13件、Day2が11件と盛りだくさんで、発表2つごとに休憩が入るペースなんですね」「リモート開催は自分のペースで見られるのがありがたい」
「今回は託児サポートも行われるそうです↓」「お〜、技術系のオンラインイベントとしては珍しいかも」「最寄りの外部託児サービスの費用を先着20名まで負担する形なんですね」「託児サービスの運営はさまざまな面で気を遣う部分が増えるので、こういう形式にしたのもわかる」
/#kaigionrails では
託児サポートを実施します!!
\参加したいけれど家だと子どもがいて集中できない…
土曜日だから保育園はお休みだけど、このセッションは見たい〜!!
そんな声に応えたいと思います!事前申し込みが必要です。ぜひご検討ください!!https://t.co/eIE7thHYts— Kaigi on Rails (@kaigionrails) September 23, 2022
以下はつっつき後に見つけたツイートです。プレイベントもお見逃しなく。
Kaigi on Rails 2022の公式グッズ販売を始めました📢
パーカー・Tシャツ・ステッカーに加え、今年はミニクリアケースやエコバックのラインナップをご用意しました!
商品到着まで10日程度かかります。イベント当日までに届くようお早めにお買い求めください💨https://t.co/ms0NdOy8vl#kaigionrails— Kaigi on Rails (@kaigionrails) September 30, 2022
【宣伝】
Kaigi on Railsでは今月2つのイベントを開催します。まずは10月9日(日)にプレイベント、"Kaigi on Rails _2022_ new"があります。こちらは本編の紹介とLT会で構成されています。LT枠は10名分あり、まだまだ募集中ですのでぜひ登壇してみてください!https://t.co/MKQVZxKE1o#kaigionrails
— 大倉雅史(OKURA Masafumi) (@okuramasafumi) October 2, 2022
🔗 書籍『Practicing Rails』
そう、この本めっちゃいいんですよ!「初学者でもくじけないRailsの学び方」が学べる本です。問題はお値段ですよね〜。初学者向けなんだからもう少し気軽に手を出しやすい価格だったら、って思います😅 / “Practicing Railsの良さを広めたい - Eat, Play, Nap and Code” https://t.co/OzeDvLPVgn
— Junichi Ito (伊藤淳一) (@jnchito) September 27, 2022
つっつきボイス:「jnchitoさんのツイートを見るまでPracticing Railsを知りませんでした」「Railsチュートリアル™が終わったぐらいの人を対象にしているようですね」「サイトを見るとRails 5.1が最新だった時期に書かれたそうです」「Rails 5.1の頃ならWebpackerの話は入っていなさそうだからRails 7の時代に合わせて読みやすいかも」
「この本はRailsを学習するときのガイド的な位置づけで、コミュニティーとの繋がり方などにも言及しているようですね」「具体的な技術を解説する書籍だとどうしても古くなりがちですが、この本の場合は古くなった記述とそうでない記述を見分ける力がある程度必要だろうとは思うものの、今の時代に読んでもよさそう👍」「Railsの基本設計や理念がこれまで大きく変わっていないのはありがたいですね」「これに限らず、本は読む人との相性や読んだ時点のスキルといった要素も大きいので一概には言えませんが、自分に合っていそうと思ったらどんどん読んでみるのがいいと思います」「やっぱり本は出会いですね」
🔗 holidays: 休日を扱うgem(Ruby Weeklyより)
つっつきボイス:「これまでウォッチで取り上げていそうでいなかったgemで、日本語も対応しているようです」「こういうgemは昔からあって使われていますね」
後で動かしてみました。
>> require 'holidays'
>> Holidays.year_holidays([:jp], Date.civil(2022, 1, 1))
=>
[{:date=>#<Date: 2022-01-01 ((2459581j,0s,0n),+0s,2299161j)>, :name=>"元日", :regions=>[:jp]},
{:date=>#<Date: 2022-01-10 ((2459590j,0s,0n),+0s,2299161j)>,
:name=>"成人の日",
:regions=>[:jp]},
{:date=>#<Date: 2022-02-11 ((2459622j,0s,0n),+0s,2299161j)>,
:name=>"建国記念の日",
:regions=>[:jp]},
{:date=>#<Date: 2022-02-23 ((2459634j,0s,0n),+0s,2299161j)>,
:name=>"天皇誕生日",
:regions=>[:jp]},
{:date=>#<Date: 2022-03-21 ((2459660j,0s,0n),+0s,2299161j)>,
:name=>"春分の日",
:regions=>[:jp]},
{:date=>#<Date: 2022-04-29 ((2459699j,0s,0n),+0s,2299161j)>,
:name=>"昭和の日",
:regions=>[:jp]},
{:date=>#<Date: 2022-05-03 ((2459703j,0s,0n),+0s,2299161j)>,
:name=>"憲法記念日",
:regions=>[:jp]},
{:date=>#<Date: 2022-05-04 ((2459704j,0s,0n),+0s,2299161j)>,
:name=>"みどりの日",
:regions=>[:jp]},
{:date=>#<Date: 2022-05-05 ((2459705j,0s,0n),+0s,2299161j)>,
:name=>"こどもの日",
:regions=>[:jp]},
{:date=>#<Date: 2022-07-18 ((2459779j,0s,0n),+0s,2299161j)>, :name=>"海の日", :regions=>[:jp]},
{:date=>#<Date: 2022-08-11 ((2459803j,0s,0n),+0s,2299161j)>, :name=>"山の日", :regions=>[:jp]},
{:date=>#<Date: 2022-09-19 ((2459842j,0s,0n),+0s,2299161j)>,
:name=>"敬老の日",
:regions=>[:jp]},
{:date=>#<Date: 2022-09-23 ((2459846j,0s,0n),+0s,2299161j)>,
:name=>"秋分の日",
:regions=>[:jp]},
{:date=>#<Date: 2022-10-10 ((2459863j,0s,0n),+0s,2299161j)>,
:name=>"スポーツの日",
:regions=>[:jp]},
{:date=>#<Date: 2022-11-03 ((2459887j,0s,0n),+0s,2299161j)>,
:name=>"文化の日",
:regions=>[:jp]},
{:date=>#<Date: 2022-11-23 ((2459907j,0s,0n),+0s,2299161j)>,
:name=>"勤労感謝の日",
:regions=>[:jp]}]
「たしか小規模なプロジェクトでこのあたりのgemを使った覚えがあります↓」
「休日は年によって変わるのでちゃんと扱おうとすると大変: たしか日本の祝日は前年の特定の時期に決まるんじゃなかったかな」「この間のオリンピックでも紙のカレンダーが使えなくなったりしましたよね」「そうそう」
「以下のphonelibなんかもそうですが、こういうふうにデータを内蔵しているgemを使うときは、その後のデータ更新に追従する覚悟が必要」「そうそう、GitHubのDependabotがちょくちょく知らせてきたりしますよね」「単なる追加更新ぐらいならまだしも、国が増えたり減ったりする可能性もあるので油断できない」
参考: Configuring Dependabot security updates - GitHub Docs
🔗 その他Rails
あと、例外処理のお話もしましたが、チェリー本の内容に加えて、このスライドも見ておくと良いです。例外処理にまつわる「本当にあった怖い話」が読めます👻https://t.co/30kqFCbqMF
安易にrescueしちゃダメよ、っていう話はこちらの動画でも説明してます。https://t.co/mFMXEoM41H
— Junichi Ito (伊藤淳一) (@jnchito) September 26, 2022
つっつきボイス:「jnchitoさんの記事: 本を端から読んで全部理解しようとするよりも、最初は脳内インデックスを作るつもりで、読み飛ばしながらでも一度最後まで読む方がいいと自分も思います」「そうそう、知らないものは探しようがないですよね」「学生の頃はオライリー本を意味もわからないままとにかく最後まで読んでました」「その後も定期的に脳内インデックスと用語を更新するのが大事: この週刊Railsウォッチのつっつき会がちょうど自分にとってそういう場になっていますね」
「2つ目のツイートの動画とスライドはRailsの例外処理の話で、Qiita記事にjnchitoさんがコメントを付けています」「元記事の冒頭にあるような書き方はたしかにつらいですね: トランザクションブロックの中でDBトランザクションに関係のないリダイレクトを行うと、例外発生時に想定外のロールバックが発生して処理がどう進むかを追うのが難しくなるので、自分なら少なくともrespond_to
はトランザクションの外に書きます」「あ、たしかに」「トランザクションを書くとエラー時にロールバックするようになって処理が複雑になるので安易に書くべきではないと思いますし、書くとしても基本的にトランザクションの中にDBトランザクション以外の処理はなるべく書かない方がよいと思います」
「そしてツイートでも指摘されているように、rescue
も安易に使うとロールバックが握りつぶされるので要注意」「たしかに」「やむを得ず使う場合でも、どのエラーオブジェクトをrescue
するかをしっかり指定する必要があります」
参考: 制御構造 (Ruby 3.1 リファレンスマニュアル)
「そういえば例外ツリーの根っこにあるException
クラスをrescue
で指定するのはよくないという記事を見たことがありました」「単なる投機的な処理のためにException
を指定してすべての例外を雑に拾う程度ならさして問題ではないかな(その分どこで例外が発生したかを突き止めるのが大変ですが)」「なるほど」「でも、たとえばメール送信のような重要な処理を含む場合にException
クラスを指定するのは本当にヤバいのでやめるべき: 最悪の場合本来行うべき例外処理が行われなくなったり例外ログが適切に出力されなくなったりしてしまいます」
参考: class Exception
(Ruby 3.1 リファレンスマニュアル)
前編は以上です。
バックナンバー(2022年度第3四半期)
週刊Railsウォッチ: CRuby 3.2にオブジェクトシェイプがマージ、Cloudflare R2ほか(20220927後編)
- 20220926前編 Rack 3アップグレードガイド、Stimpack gemほか
- 20220920 Ruby 3.2.0 Preview 2とRack 3.0リリース、packwerkでアプリコードの境界を強制ほか
- 20220906後編 syntax_suggestがRuby標準ライブラリに追加、RubyのVisitorパターンほか
- 20220905前編 Herokuが無料プラン廃止を発表、Hotwire日本語コミュニティほか
- 20220830後編 RubyKaigi 2022タイムテーブル公開、viewport-extraほか
- 20220829前編 MinitestとRSpecの比較、商用版NGINXの重要機能がオープンソース化ほか
- 20220823後編 byebugからruby/debugへの移行ガイド、YJIT解説記事ほ
- 20220822前編 ビューテンプレートに渡せるローカル変数をマジックコメントでチェック可能にほか
- 20220802後編 RubyのGVLトレーサーgvl-tracing、casting gemでオブジェクトに振る舞いを追加ほか
- 20220801前編 “リーダブルテストコードについて考えよう”スライド公開、Evil Martiansが日本上陸ほか
- 20220726後編 中高生国際Rubyプログラミングコンテスト2022、W3Cの分散型識別子仕様が勧告にほか
- 20220725前編 RailsConf 2022の動画が公開、マイクロサービスのテスト戦略ほか(
- 20220719 RubyのGCが高速化、RuboCopのストレスを減らす4つの方法、Defensive CSSほか
- 20220711前編 AR::RelationにCTEを利用できるwithメソッドが追加、Propshaftアップグレードガイドほか
- 20220705後編 6月のRubyコア動向、Stack Overflowアンケート結果ほか
- 20220704前編 マイグレーションをStrategyパターンで拡張可能にほか
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。
週刊Railsウォッチについて
TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)