- Ruby / Rails関連
週刊Railsウォッチ(20200928前編)Ruby 3.0.0 Preview 1リリース、Rails Guidesにconcernsのドキュメント追加、Sidekiq 2020エディションほか
こんにちは、hachi8833です。次はKaigi on Railsですね。
Kaigi on Rails公式サイトにてスポンサーページが公開になりました🎉https://t.co/50GJzK6Nr3
開催が来週末に迫ってきました!10/3(土)10:00〜オンライン配信します。#kaigionrails— Kaigi on Rails (@kaigionrails) September 21, 2020
つっつきボイス:「10月3日といえばもうすぐか」「Reject Kaigi on Railsも前日に開催されるそうです↓」「お〜Reject Kaigiもやるとは!」「Rejectが金曜日夜でKaigi on Railsが土曜日終日ですね」
Hamada.rbでReject Kaigi on Railsやります!!! https://t.co/UIZteauBK0
— Hamada.rb (@RbHamada) September 21, 2020
「グッズも出てるそうです↓」「このスズリみたいに1個単位で扱えるところは運営の負担が小さいのがいいですよね☺️」
参考: kaigionrailsのオリジナルアイテム通販 ∞ SUZURI(スズリ)
なお、つい先ほど以下の見どころ記事を知りました。ご参考まで。
参考: Kaigi on Rails に koic, 9sako6, yucao24hours が登壇!見どころをご紹介します - esm アジャイル事業部 開発者ブログ
- 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
- 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
⚓ 臨時ニュース: Ruby 3.0.0 Preview 1がリリース
つっつき会後の先週土曜日にリリースされました。
Ruby 3.0.0 Preview 1 Released https://t.co/o6lkjD5PKw
— Ruby Language (@rubylangorg) September 25, 2020
- リリース情報: Ruby 3.0.0 Preview 1 Released
RBS、Ractor、Thread#scheduler
、右代入、endレスメソッド定義など盛りだくさんのPreview 1です。
参考: ruby/ractor.ja.md at ractor · ko1/ruby
私も早速以下の手順で3.0.0-preview1をインストールしてみました。
Ruby 3.0.0-preview1、早速インストールしてみたよ〜。
手順はこんな感じです👇https://t.co/UpYp2fkLGE https://t.co/9HgZlufsNq pic.twitter.com/JURb97zHKY
— Junichi Ito (伊藤淳一) (@jnchito) September 26, 2020
⚓Rails: 先週の改修(Rails公式ニュースより)
以下のコミットリストのChangelogを中心に見繕いました。
- コミットリスト: Comparing master@{2020-09-11}...@{2020-09-24} · rails/rails
- マイルストーン: 6.1.0 Milestone -- 31件
つっつきボイス:「due dateは設定されてないけどマイルストーンが73%まで完了してる」「issueの件数がちょっと増えましたね」
⚓RailsのGetting Startedガイドにconcernsセクションを追加
以下のディスカッションで知りました。
参考: Helping devs understand concerns faster - A May Of WTFs - Ruby on Rails Discussions
なお、Edgeguidesでこのconcernsドキュメントを読めます↓。
参考: 7.3 Using Concerns -- Getting Started with Rails — Ruby on Rails Guides
つっつきボイス:「Railsのconcernsをどう使うかという詳しい情報がついにRailsガイドに公式に追加されるそうです」「あれ、今までなかった?」「concerns、自分はあんまり好きじゃないけど、Railsではデフォルトでconcerns/ディレクトリが作られるし、concernsの公式ドキュメントはある方がいいでしょうね」
「ところで、concernsがぴったり合うコードというか、concernsで何かをきれいに解決できたのを見たことってごくごくまれにしかないんですよね😆」「たいてい特定のコントローラや特定のモデルのためのconcernsだったりしますし😆」「ソースコードを分割するためだけのconcernsとか、まあそれはそれでありかなと思いますけど」
「以下のAppSignalのconcerns記事↓はまだ読んでませんが、内容が近そうなのでここに貼っておきます」
⚓ActionDispatch::Http::Request#POST
で無効なUTF-8エンコーディングを検出
つっつきボイス:「テストコードを見ると、invalidなUTF-8文字がPOSTパラメーターに含まれるときにうまくいかなかったらしい」「ははぁ、この%81E
っていうのがUTF-8にない文字か↓」「"application/x-www-form-urlencoded; charset=utf-8"
を指定してるのにinvalidなUTF-8文字でエラーが正しく出てなかったのを対応したんでしょうね」「%81E
みたいな文字がPOSTされることってありそう...」
# actionpack/test/dispatch/request_test.rb#L1054
+ test "POST parameters containing invalid UTF8 character" do
+ data = "foo=%81E"
+ request = stub_request(
+ "REQUEST_METHOD" => "POST",
+ "CONTENT_LENGTH" => data.length,
+ "CONTENT_TYPE" => "application/x-www-form-urlencoded; charset=utf-8",
+ "rack.input" => StringIO.new(data)
+ )
+
+ err = assert_raises(ActionController::BadRequest) { request.parameters }
+
+ assert_predicate err.message, :valid_encoding?
+ assert_equal "Invalid request parameters: Invalid encoding for parameter: �E", err.message
+ end
このプルリクでは2つのことを行っている。
1. この修正と同様に、ActionDispatch::Http::Request#POST
でRequest::Utils.check_param_encoding(params)
を呼ぶべき。現在はPOSTリクエストで不正な入力がコントローラに到達してしまうので、スタックでさらに例外をraiseすることでコントローラにこういうものが到達しないようにして不正なエンコーディングの入力を禁止すべき。
2. バイナリエンコーディング周りのロジックを若干変更。従来ActionDispatch::Http::Parameters#parameters
のコントロールフローは以下のような感じだった。
query_params
を取得(paramエンコーディングをチェックしていた)request_params
でマージ(これはparamエンコーディングをチェックして「いなかった」)path_parameters
でマージ(これはバイナリにエンコードされ、その後エンコーディングが設定された時点でエンコーディングをチェックする、こちらを参照)- バイナリエンコーディングを実行(必要な場合)
今は
GET
やPOST
で無効なエンコーディングをraiseするようになっているので、ActionDispatch::Http::Request
でバイナリエンコーディングが行われるようにして、コントローラが望んでいないエンコーディングがバイナリにある場合にのみinvalid encoding例外を出すようにする必要がある。そのためには以下の変更が必要だった。
- バイナリエンコーディングのロジックを
ActionDispatch::Request::Utils
に切り出すGET
やPOST
でエンコーディングをチェックするより前にActionDispatch::Request::Utils#set_binary_encoding
呼び出しを追加するActionDispatch::Http::Parameters#path_parameters=
を変更して新しいインターフェイスを用いるようにし、ActionDispatch::Http::Parameters
からバイナリエンコーディングのロジックを削除するActionDispatch::Http::Parameters#parameters
で#set_binary_encoding
の余分な呼び出しを削除する(GET
やPOST
やpath_parameters
はすべてエンコーディングチェックより前の段階でのバイナリへのエンコーディングを義務付けられたため)
同PRより大意
⚓SKIP_TEST_DATABASE
環境変数を追加
つっつきボイス:「なるほど、dbのセットアップでテスト用データベースを作らないようにしたい、それを環境変数で制御したいと」「Dockerでこのオプションが使いたいときとかありそう」
➜ SKIP_TEST_DATABASE=true bundle exec rake db:create
Created database 'db/development.sqlite3'
➜ bundle exec rake db:create
Created database 'db/development.sqlite3'
Created database 'db/test.sqlite3'
「Railsでdb:create
をするとテスト用dbも作られちゃうんですよね」「たしかに」「そういうのが要らないときにこうやって指定できるといいでしょうね👍」
⚓Mysql2Adapter#quote_string
のMySQL2エラーを変換
つっつきボイス:「一度取り下げたプルリクをリトライしてマージされたそうです」「take 2ってそういうことですか」「コネクションアダプタごとに振る舞いが異なっていた部分を揃えたように見える」
- すべてのコネクションアダプタの
execute
が、コネクションエラー時にActiveRecord::InvalidStatement
ではなくActiveRecord::ConnectionNotEstablished
をraiseするようになった。Mysql2Adapter#quote_string
が、MySQLサーバーに接続できなかった場合にActiveRecord::InvalidStatement
ではなくActiveRecord::ConnectionNotEstablished
をraiseするようになった。
同PRより大意
「どういうときにquote_string
が失敗するんだろう?」「#40148を見るとMysql2::Client#escape
ではmysql_real_escape_string
というC APIを使っていて、これは健全なコネクションが存在しないと動かないからって書かれている」「へぇ〜!」「その理由はコネクションのロケールによって振る舞いが変わるからか、なるほどなるほど」
「つまりこのAPIが失敗するということは健全なコネクションが存在しないことが原因なので、ステートメントが間違ってないのにInvalidStatement
を返すのは不適切で、ConnectionNotEstablished
の方が適切という判断なんでしょうね」「なるほど!」
⚓ActiveSupport::Subscriber.attach_to
にinherit_all
オプションを追加
つっつきボイス:「あるとたぶんうれしい機能」「へぇ〜、こういうユースケースがあるとは」
ActiveSupport::Subscriber.attach_to
でinherit_all
オプションを受け取れるようにする。これは以下のように、サブスクライバーがその先祖クラス内のメソッドのイベントにもサブスクライブできるようにすべきかどうかを指定する。
class ActionController::LogSubscriber < ActiveSupport::LogSubscriber
def start_processing
end
end
class CustomLogSubscriber < ActionController::LogSubscriber
attach_to :action_controller, inherit_all: true
end
これで
CustomLogSubscriber
はstart_processing
のイベントにもサブスクライブする。
ただし新しいイベントサブスクライバーを登録する場合はActiveSupport::Subscriber
やActiveSupport::LogSubscriber
内のpublicメソッドを無視している。
同PRより大意
⚓Rails
⚓小さくてレビューしやすいプルリクのガイド
- 元記事: A practical guide to small and easy-to-review pull requests | by Jens Jakob Balvig | Source Diving
クックパッドの中の人の記事です。
つっつきボイス:「以下の2つを実践したらプルリクがapproveされるまでの時間などが改善されたそうです」「"less than 100 additions"ってあるのはたぶん行数のことかな」「そんな感じでしょうね」「あ、そうかも」「単位がないと意味わかりませんし😆」
- プルリクの追加は100行以下にすることを推奨
- 完成していない機能でもmasterへのマージを許す
「実際、masterに入れても影響が生じないようにプルリクを作るのは大事ですよね👍」「特に大人数になればなるほどこういう縛りが必要になってきたりしますし」
「先行してmasterに入れておかないといけない機能ってよくあるので、これはとてもわかる」「そうしないとrebaseがどんどん重くなっちゃいますし」「rebaseを小さくするには、マージしても壊れない程度の粒度でプルリクして欲しいですよね」
⚓Railsでconstantize
を避けるべきもうひとつの理由(Ruby Weeklyより)
つっつきボイス:「Railsのconstantize
はセキュリティに注意しようってよく言われるヤツですね」
- Rails API:
String#constantize
「ははぁ、const_missing
を使っているgemがたまにあるから、const_missing
がオーバーライドされると思わぬ挙動を招くということか」「簡単にexploitできちゃうって書かれてますね」
# 同記事より
2.7.0 :001 > module X
2.7.0 :002 > def self.const_missing(name)
2.7.0 :003 > puts "You tried to load #{name.inspect}"
2.7.0 :004 > end
2.7.0 :005 > end
=> :const_missing
2.7.0 :006 > X::Hello
You tried to load :Hello
=> nil
「安全のためにはRailsのclassify
を使いましょうということらしい↓」「このメソッド初めて知りました」「constantize
、実は使ったことありますけど、constantize
が危険なのは前々からわかっているので、ちゃんとホワイトリストと照合してから使いましたし」「任意の文字列を取れるように書いたらダメですよね😆」
- Rails API:
String#classify
結論: Railsで
constantize
の利用は避けること。どうしても必要な場合はconstantize
を呼ぶ前に使ってよいクラス名リストと照合すること(チェックの前にclassify
を呼び出すのは問題ないが)。
(中略)
編集: 本記事の書き方の一部が少々曖昧だったようなので修正した。classify
を呼んでもコードが安全になるわけではない。classify
の呼び出し自体に害はないが、その後でconstantize
を呼ぶことが危険だと言いたかった。つまりclassify
を安全に呼び出して、許可されたクラス名リストと照合してから適切な操作を行える。
同記事より抜粋・大意
⚓Sidekiq 2020エディションの新機能(Ruby Weeklyより)
つっつきボイス:「Sidekiq 2020の新機能だそうです」「ジョブエンジンをどれにするかは悩ましいんですよね、どうやっても複雑になるので」
「SidekiqにPro版とEnterprise版もあるって初めて知りました」「へぇ〜、Enterpriseだとrate limitやsidekiqswarmも使えるのね」「Sidekiqの無料版でもプロセス数を増やせるようになったらいいな〜と思ったら、マルチプロセスはEnterproseのみか、残念😢」
前編は以上です。
バックナンバー(2020年度第3四半期)
週刊Railsウォッチ(20200915後編)RubyKaigi 2020 Takeoutの動画出揃う、イタリア語でRuby、AWS Summit Online開催中ほか
- 20200914前編 10月のKaigi on Rails情報発表、JS入れ過ぎRailsアプリ、テストで便利なpuffing-billy gemほか
- 20200908後編 Shopify版Rubyスタイルガイド、JavaScript Primerが2.0に、GitHub Container Registryほか
- 20200901後編 RubyKaigi 2020 Takeout登壇者発表、Ruby開発版が2.8から3.0へ、マイクロサービス分割ほか
- 20200831前編 GitHubがRuby 2.7にアップグレード、Durationに変換メソッドが追加、hair_triggerでデータベーストリガほか
- 20200825後編 Rubyクラスライブラリをgem化、Rubyテストフレームワークrr、ChromebookでWindowsが動くほか
- 20200824前編 「Active Jobスタイルガイド」は有用、SiderがGitLabに対応、eager loading時のselectを修正ほか
- 20200818後編 ruby_jardデバッガがスゴい、RubyオンラインマニュアルにEdit機能が追加、Ruby 2.7のBundlerを消す方法ほか
- 20200817前編 お盆も続くRails改修、Rails 6.1にManyモナドが入る?rails-auth gemでクライアント認証ほか
- 20200811山の日短縮版 RSpec Queueでパラレルテスト、カロリーメイトとRubyのコラボ、Rubyのcoercionほか
- 20200804後編 「RubyKaigi Takeout 2020」9月オンライン開催、メールバリデータtruemail、Gitのmasterが変更可能にほか
- 20200803前編 書籍『パーフェクトRuby on Rails』増補改訂版、マルチDBで抽象クラスをscaffold生成、GitLabがPumaに乗り換えほか
- 20200721後編 『パーフェクトRuby on Rails』増補改訂版発売間近、scan_left gemでレイジーなinjectほか
- 20200720前編 10月開催「Kaigi on Rails」CFP募集中、enumにデフォルト値設定機能、RailsでBitemporal Data Modelほか
- 20200714後編 ruby-warning gemでワーニングを手軽に抑制、rubocop -aの振る舞いが変わる、書籍『MySQL徹底入門 第4版』ほか
- 20200713前編 rspec-openapiでスキーマ自動生成、Rails Architect Conf動画、
where()
ハッシュキーに比較演算子条件を書ける機能ほか - 20200707後編 Rubyで無名structリテラル提案、書籍『AWS認定ソリューションアーキテクト』、21世紀のC言語ほか
- 20200706前編 Railsでのマルチテナンシー実装戦略を比較、Railsでサブクエリを使う、URI.parserが非推奨化ほか)
今週の主なニュースソース
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。