- Ruby / Rails関連
週刊Railsウォッチ:(20211108前編)RubyKaigiの過去講演動画が多数公開、Active ResourceとHerほか
こんにちは、hachi8833です。
🔗Rails: 先週の改修(Rails公式ニュースより)
今回は以下の公式更新情報から見繕いました。件数が多いので残りは次回に。
🔗 ActiveRecord::Base.prohibit_shard_swapping
を追加
- PR: Add `ActiveRecord::Base.prohibit_shard_swapping` by seejohnrun · Pull Request #43485 · rails/rails
シャーディング化したデータベースをリクエストのライフサイクル全体で用いる場合、データベースのシャードが意図せず変更されないことが望ましいことがよくある。
このコミットはActiveRecord::Base.prohibit_shard_swapping
を導入する。これはブロックを受け取って、ブロックが継続中にシャードのスワップが発生しないようにするというもの。
同PRより
つっつきボイス:「シャーディング(sharding: 水平分散)でスワップが発生しないようにするとは?」「データベースのシャーディングでは、複数あるシャードのどれにデータを置くかをハッシュ関数などで決定します」「ちょっとRAID 5みたいですね」
参考: DBのテーブル水平分割技術「シャーディング」とは | 若手エンジニアのブログ
参考: RAID - Wikipedia
参考: ハッシュ関数 - Wikipedia
「で、シャーディングのキーとなるカラムが更新されるとブロックの置き場所が変わるんですよ」「あ、そうか」「おそらくシャードのスワッピングはそのことを指しているんでしょうね: この改修は、prohibit_shard_swapping
ブロック内ではそういうシャードの移動が発生しないようにすることだと思います」「なるほど」
🔗 schema/structureダンプのファイルパスを指定可能に
従来のRailsでは、schema/structureダンプの生成がデータベースの設定名に基づいていた。discuss.rubyonrails.orgでの議論にもあるように、これはシャード間でdumpファイルを共有するうえで問題がある。
このプルリクによる機能は、スキーマダンプのファイル名を設定するカスタムソリューションを既に書いていて、それを使いたい場合に便利。スキーマキャッシュのパスを指定できるのだから、スキーマダンプでもそうしない手はないだろう。
そのために、古いschema_fileデータベースタスクを非推奨にして、代わりに新しい方法でdb_config
を渡せるようにした。db_config
からファイル名を決定するコードはここで重複することになるが、将来はこれがファイル名決定の正しい方法になる。これらはコンフィグに設定されるのでアプリのコンフィグでもアクセス可能なはず。
なおschema_dumpはアルファ版以外のどのリリースにも含まれていないので、schema_dumpの振る舞いを非推奨化の手続きに乗せる必要はなかった。ただしfalse
とnil
の場合の振る舞いは同じ。
* #43173をクローズ
* #43240に取って代わる
共著: Ryan Kerr leboshi@gmail.com
同PRより
つっつきボイス:「なるほど、schema/structureのダンプ先を指定できるようになったんですね: これはいいことだと思う👍」「ありがたい🙏」「今まではできなかったとは」「スキーマダンプのコマンドはrails db:schema:dump
でしたね」
🔗 Rails 7でselenium-webdriver 4以上とwebdrivers 5をサポート
新しいRails 7.0のジェネレータが生成するGemfileでは、Ruby 3.0をサポートするselenium-webdriver 4.0.0以上(#43270)と、それを必要とする最新のwebdrivers 5.0.0が使われる。
https://rubygems.org/gems/webdrivers/versions/5.0.0
そろそろRails 7.0でselenium-webdriver 3.xのサポートを廃止するとき。
同PRより
つっつきボイス:「selenium-webdriverのバージョンがRails 7から上がる: 既存アプリによってはRails 7にアップグレードするときのシステムテストの更新がちょっと大変になるかも」「システムテストをみっちり書いているアプリほどつらそう...」「自分はそこまでシステムテストをびっちり書かないかな」
🔗 monotonic_time
をRubyネイティブの機能に置き換え
つっつきボイス:「これはリファクタリングか」「Ruby公式のProcess.clock_gettime
があるならそれを使おうという流れのようですね」
# activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb#L530
newly_checked_out = []
- timeout_time = Concurrent.monotonic_time + (@checkout_timeout * 2)
+ timeout_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) + (@checkout_timeout * 2)
@available.with_a_bias_for(Thread.current) do
loop do
synchronize do
return if collected_conns.size == @connections.size && @now_connecting == 0
- remaining_timeout = timeout_time - Concurrent.monotonic_time
+ remaining_timeout = timeout_time - Process.clock_gettime(Process::CLOCK_MONOTONIC)
remaining_timeout = 0 if remaining_timeout < 0
conn = checkout_for_exclusive_access(remaining_timeout)
collected_conns << conn
newly_checked_out << conn
end
end
参考: Process::CLOCK_MONOTONIC
(Ruby 3.0.0 リファレンスマニュアル)
「従来のmonotonic_time
はconcurrent-rubyの機能なのかな?」「ググって出てきた過去記事↓を見ると、Rails 6でconcurrent-rubyがActive Supportに導入されているので(#32034)そのようですね: インターフェイスが少し変わるのでバックポートまではしなさそうですが」
🔗 CI環境でデフォルトのeager loadingをサポート
このパターンはShopifyで長年使われている。
テストをローカル実行するときはほとんどの場合テストの一部しか実行しないので、最初のテスト結果が出るまでの時間を短縮するには読み出すコードができるだけ少ない方がよい。
CIの場合はいずれにしろすべてのテストコードを読み込むのだし、テストスイートが複数のランナーに分散する場合でも副作用のあるコードファイルを確実に読み込むために、アプリケーションをeager loadingする方が望ましい。
これにより、オートロードされた定数がCI上で適切にテストされていない場合であっても、少なくともデプロイ時より前にCIで読み込まれてSyntaxErrorなどのエラーが明示的に出るようになる。
同PRより
つっつきボイス:「config.eager_load = ENV["CI"].present?
がコンフィグにデフォルトで追加されるのね」「CIという環境変数は使ったことなかったな〜」
🔗 Classic->Zeitwerkガイド
つっつきボイス:「お〜、Zeitwerkへの移行ガイドがedgeに上がった」「本家英語版ガイドではまだですが、日本語版Railsガイド向けに日本語訳をWIPで準備中です↓」「Railsガイドってこういうふうに翻訳してるのか〜」「なるほど、英語版のmarkdownファイルと別にjpディレクトリに日本語版markdownファイルを置いているんですね」「そうしないと自分がバージョンを追えなくなってしまいそうなので😅」
参考: [WIP]Zeitwerkアップグレードガイド by hachi8833 · Pull Request #1093 · yasslab/railsguides.jp
🔗Rails
🔗 RubyKaigiの過去動画が多数公開
つっつきボイス:「先週の大江戸Ruby会議09出前Editionで、RubyKaigiの過去の講演動画アーカイブが多数お披露目されましたね(イベント後に公開されました)」「2006〜2008年でこれだけの数の動画スゴい」「貴重な動画を掘り起こしてくれてありがたいです🙏」「紹介されていた動画がどれもすんごくよかった」「全部見る時間あるかな...」「YouTubeなら英語字幕も付くので気楽に見てみるといいと思います」「今見るとさらに増えているみたい」「あ、ホントだ」
🔗 DHHによるRails解説「One controller, many ins, many outs」
「圧巻は、冒頭でみんなで視聴した若き日のDHHによるRails解説↓」「このときのDHHは20代だったのが信じがたい」「CRUDやRESTとの関連など、今見てもまったく色あせない内容なのがホントすごい」
Railsが今のURI設計に大きな影響を与えたとは知らなかった。自分は最近勉強始めたからRESTとかCRUDは当たり前にあるものだったけど、当時はすごく革新的だったことがわかって面白かった🔥 #oedo09
— オブレゴニア (@obregonia1) November 3, 2021
🔗 Matzを説得する方法
「このHow to persuade matzという動画もとてもおもしろかった↓」
「matzを説得する方法 How to persuade matz」なんだけど、普通に OSS にコントリビュートするときに参考に出来る教科書 https://t.co/kmlAa5gfq4
— Watson (@watson1978) November 2, 2021
🔗 The Island of Ruby
「Dave Thomas氏がRubyへの愛を熱烈に語った動画もよかった↓」「Rubyは今後こういうことをしなければならないという話をこの時代にしていたのが改めてすごいと思いました」「大江戸Ruby会議09は、他にも自分の知らない時代のRubyの話が山盛り」「そうそう、知らない話が続々出てきました」
参考: #8 達人プログラマー Dave Thomas(前編) RubyにはMatzの受けた教育,宗教とかすべてが反映されている:小飼弾のアルファギークに逢いたい♥|gihyo.jp … 技術評論社
🔗 HTTPClient gem
「こちらはVimeoに上がっている動画ですが、自分が大好きなHTTPClient gemの作者である@nahiさんの発表が個人的にとても刺さりました↓」「そういえば以前からHTTPClientを推してましたね」「HTTPClientで自分のやりたいことが全部できるのは、この方が既存のHTTPクライアントで何がサポートされて何がサポートされていないかをこんなに詳しくサーベイしていたからなんだなというのがとてもよくわかる動画」「お〜これは細かい!」「この動画を見て、改めて今後もHTTPClientを使おうという気持ちになりました: 自分でRubyのHTTPクライアントライブラリを選定したことのある人には響くんじゃないかな」
大江戸HTTPクライアント絵巻 / @nahi from ogi on Vimeo.
「視聴中に寝落ちしてこのあたりを見られませんでした...」「自分も懇親会の記憶があまりない😆」
🔗 Active ResourceとHer
「ところで、DHHの講演の中でActive ResourceというものがRailsの機能として登場していて"こんな機能あったかな?"と思ったら、v3.2.6あたりを最後にgemに切り出されていたんですね↓」「Active Resourceは、Railsが描いた未来の姿のひとつとしてかなり昔からあります」
- Rails v3.2.6 API
ActiveResource::Base
なお、apidock.comにもActive Resourceはありませんでした。
「ちなみに、Active Resourceのような機能を今やるのであれば、herというライブラリがかなりメジャーです↓」「her、そういえば以前もお話しされてましたね」「自分は今もよくherを使っています」
# remi/herより
User.all
# GET "https://api.example.com/users" and return an array of User objects
User.find(1)
# GET "https://api.example.com/users/1" and return a User object
@user = User.create(fullname: "Tobias Fünke")
# POST "https://api.example.com/users" with `fullname=Tobias+Fünke` and return the saved User object
@user = User.new(fullname: "Tobias Fünke")
@user.occupation = "actor"
@user.save
# POST "https://api.example.com/users" with `fullname=Tobias+Fünke&occupation=actor` and return the saved User object
@user = User.find(1)
@user.fullname = "Lindsay Fünke"
@user.save
# PUT "https://api.example.com/users/1" with `fullname=Lindsay+Fünke` and return the updated User object
「RESTfulに実装されているAPIサーバーであれば、あたかもActive Recordのようなインターフェースでデータの取得・更新ができて、たとえばfind(1)
してsave
すると"https://api.example.com/users/1
をPUTしたりする」「お〜、そういうことができるんですか、これいいな〜」「ただしwhere
のようなメソッドはAPI側が対応する必要がありますし、当然or
やjoin
みたいなことはできないので、Active Recordとすべて同じというわけにはいきませんが、idで取ってくるような処理なら十分使えます」「なるほど」
「Active Resourceはほとんど更新されなくなっていますね、もっともherも直近のリリースは2019年ですが」「たしかに」「herは以下のようにアダプタがモジュラブルになっていて使いやすいですし↓、Active Recordを継承しているわけではないのでRailsへの依存も小さいはず: 今Active Resourceのようなことをするならherだと自分は思っています」
# remi/herより
# config/initializers/her.rb
Her::API.setup url: "https://api.example.com" do |c|
# Request
c.use Faraday::Request::UrlEncoded
# Response
c.use Her::Middleware::DefaultParseJSON
# Adapter
c.use Faraday::Adapter::NetHttp
end
「Active Resourceという概念は今でも好きなので、それもあって今もherを使ってます」「マイクロサービスが流行っている今Active Resourceがカムバックしてもよかったんじゃないかというコメントを見かけましたけど、それもちょっとわかるかも」「Active Resourceは、ローカルのリソースも外部リソースも同じインターフェイスで扱えるところが強みなんですよ: おそらくDHHも自分が作ったActive Resourceという概念が念頭にあるから今もRESTfulにこだわっているのかなという気持ちに少しなりました」「ふーむ」
参考: Representational State Transfer(REST)- Wikipedia
🔗 Railsのトランザクション入門(Ruby Weeklyより)
つっつきボイス:「Railsのデータベーストランザクションの基本的な解説のようです」「トランザクションとは何か、トランザクションの作成、ロールバック、失敗したトランザクションのキャッチ、まさに入門の導入部という感じですね」
🔗 ルーティングをRESTfulにする(Ruby Weeklyより)
つっつきボイス:「ネステッドなルーティングに関する記事のようですね」
# 同記事より: RESTfulでない例
# config/routes.rb
Rails.application.routes.draw do
resources :repositories, only: %i[index show] do
resources :collaborators, only: %i[index] do
post :accept_invite
post :decline_invite
post :invite
get :show_invite
end
end
end
「上はrepositoriesの下にcollaboratorsがあるけど、なんちゃら_invite
に対応する中間モデルがないので、以下のようにinvitationsという概念を設けることでRESTfulになる、という流れですね」「なるほど」
# 同記事より: RESTfulな例
# config/routes.rb
Rails.application.routes.draw do
resources :repositories, only: %i[index show] do
resources :collaborators, only: %i[index]
resources :invitations, only: %i[show create update destroy]
end
end
「ルーティングがRESTfulになっていないということは、中間モデルが概念化されていないということ: さっきのDHHの講演動画でもまさに同じことを説明してます😆」「お〜そこにもつながるとは」
🔗 その他Rails
仕事のコードで生まれて初めてRubyのprotectedメソッドを定義したかもしれない。 #protectedメソッド記念日
— Junichi Ito (伊藤淳一) (@jnchito) November 4, 2021
つっつきボイス:「Rubyのprotected
を使うときがあったとは」「正しく使える気がしない機能」「Javaを最初に勉強するとRubyのprotected
の意味がJavaと違いすぎて頭抱えますよね」「そういえばjnchitoさんの大昔の記事でも頭抱えてました↓」「今でもわからないレベル」
参考: 呼び出し制限 -- クラス/メソッドの定義 (Ruby 3.0.0 リファレンスマニュアル)
参考: JavaやC#の常識が通用しないRubyのprivateメソッド - give IT a try
前編は以上です。
バックナンバー(2021年度第4四半期)
週刊Railsウォッチ: 2021年度Rubyアソシエーション開発助成、Rails REST APIレベルで楽観的ロックほか(20211102後編)
- 20211101前編 Rails 7アセットパイプライン解説記事、ロジックをapp/operatorsで整理ほか
- 20211026後編 YJITがRuby 3.1向けにマージ、ripperのドキュメント化、crontabの罠ほか
- 20211025前編 insert_allやupsert_allのタイムスタンプ自動更新、rails/contextsにロジックを置くほか
- 20211019後編 ruby/debugをChromeでリモートデバッグ、Rubyアプリの最適化ほか
- 20211018前編 Railsリポジトリで進行中のPropshaft、inverse_ofを自動推論ほか
- 20211012後編 Ruby 3.1にYJITマージのプロポーザル、Rubyのmagic historyメソッド、JSのPartytownほか
- 20211011前編 ServerTimingミドルウェア追加、paramsで数値キーを許可、Railsで多要素認証ほか
- 20211006後編 ruby/debug 1.2.0リリース、Railsにはthorが入っている、tendejitほか
- 20211004前編 Rails 7でbyebugがruby/debugに変更、GitHub Codespacesをサポートほか
今週の主なニュースソース
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。
週刊Railsウォッチについて
TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)