- Ruby / Rails関連
週刊Railsウォッチ: Rails向けLanguage Server "refreshing"開発中、JetBrains Fleetほか(20221018前編)
こんにちは、hachi8833です。今週はKaigi on Rails 2022ですね。
告知は諸々についてたくさんしているつもりなんだけど、それでも「知らなかった」という人を観測するので、やりすぎってくらいに告知をしたいと思います。
Kaigi on Railsは今週金曜日です!参加申し込みは以下から!!参加は無料です!!!https://t.co/pLZCJC5e3q
— 大倉雅史(OKURA Masafumi) (@okuramasafumi) October 17, 2022
🔗Rails: 先週の改修(Rails公式ニュースより)
- 公式更新情報: Ruby on Rails — ERB in YAML keys, performance boosts, a new option for QueryLogs!
- 公式更新情報: Ruby on Rails — Updated Permissions-Policy directives and LSP support?
🔗 QueryLogsでtags_format
オプションを指定可能になった
概要
このプルリクはActiveRecord::QueryLogs
にtags_format
という新しいオプションを追加する。キーバリューペアの区切りに:
を使いたくない場合がある(sqlcommenter
のように区切り文字を=
にして値を一重引用符''
で囲みたい)。そこでtag_format
オプションを追加して、:legacy
(訳注: 原文は:default
)機能と:sqlcommenter
のどちらを使うかをユーザーが指定できるようにする。
その他情報
これはMarginaliaへのプルリク(#130)を文字通りまるごとコピーした。オリジナルを実装した@modulitosに感謝。
同PRより
つっつきボイス:「そういえばQueryLogsは以前Marginaliaという名前のライブラリがRailsに取り入れられたものでしたね↓(ウォッチ20210906)」「クエリの呼び出し元情報を追加できるヤツですね」「そのクエリログのフォーマットをtags_format
オプションで変更可能になった、いいですね👍」
参考: Add Marginalia to Rails, via QueryLogs by keeran · Pull Request #42240 · rails/rails
🔗 database.ymlのYAMLキーに任意のERBを書けるようになった
コミット37d1429(#35497)で、
rake -T
実行時に環境の読み込みを回避するためにDummyERB
が導入された。
DummyCompiler
は<%=
の出力をシンプルに固定文字列に置き換えてそれ以外をすべて削除していた。これはYAMLの値で使われる場合は問題なかったが、YAMLキー内部で<%=
が使われるとYAMLパーサーでエラーが発生して期待通りのERBを利用できなくなる。たとえば以下を含むdatabase.ymlでこの問題が起きるはず。development: <% 5.times do |i| %> shard_<%= i %>: database: db/development_shard_<%= i %>.sqlite3 adapter: sqlite3 <% end %>
壊れたERBコンパイラを使う代わりに、#35468の記載通りでない設定にアクセスしてもエラーを発生しないようにする
Rails.application.config
を一時的に利用できるようになった。この変更によって
DummyCompiler
が削除されて標準のERB::Compiler
が使われるようになる。これはDummyConfig
を導入して既知のすべてのコンフィグを実際のRails::Application::Configuration
インスタンスに委譲してからそれ以外のすべてについてダミー文字列を返す。これによって、マルチプルデータベースでrakeタスクを生成するときに速度を犠牲にせずにERBとの完全互換が復元される。
config.active_record.suppress_multiple_database_warning
は非推奨化される。
同PRより
つっつきボイス:「database.ymlにERBで任意のRubyコードを書けるようになったんですか?」「今までできなかったのが意外」「すごいけどやりすぎたら怖そう」「fixtureのyamlファイルにコードを書くことはよくありますよ」
🔗 エラーの二重出力回避のためRails.error.report
を修正
- エラーの二重出力回避のために
Rails.error.report
がエラーをreportedとマーキングするようになったエラー発生前に、ユーザーが特定のコンテキストで明示的にエラーを出力したいことがある。
このプルリクによって、エラーを安全にキャッチして実行コンテキストの外でエラーを出力できるようにもなる。
Jean Boussier
同Changelogより
つっつきボイス:「エラー出力の重複を回避したそうです」「シンプルなバグ修正のようですね」
# activesupport/lib/active_support/error_reporter.rb#L169
def report(error, handled: true, severity: handled ? :warning : :error, context: {}, source: DEFAULT_SOURCE)
+ return if error.instance_variable_get(:@__rails_error_reported)
+
unless SEVERITIES.include?(severity)
raise ArgumentError, "severity must be one of #{SEVERITIES.map(&:inspect).join(", ")}, got: #{severity.inspect}"
end
full_context = ActiveSupport::ExecutionContext.to_h.merge(context)
disabled_subscribers = ActiveSupport::IsolatedExecutionState[self]
@subscribers.each do |subscriber|
unless disabled_subscribers&.any? { |s| s === subscriber }
subscriber.report(error, handled: handled, severity: severity, context: full_context, source: source)
end
rescue => subscriber_error
if logger
logger.fatal(
"Error subscriber raised an error: #{subscriber_error.message} (#{subscriber_error.class})n" +
subscriber_error.backtrace.join("n")
)
else
raise
end
end
+ unless error.frozen?
+ error.instance_variable_set(:@__rails_error_reported, true)
+ end
nil
end
end
🔗 Feature-Policy
ヘッダーのリストを更新した
- PR: Update permissions policy list by guillaumecabanel · Pull Request #45427 · rails/rails
- PR: Deprecate obsolete permissions policy directives by jonathanhefner · Pull Request #46199 · rails/rails
概要
利用可能なPermission Policyリストが進化した。
このプルリクは、安定したfeatureをActionDispatch::PermissionsPolicy
に追加する。このプルリクによってChromeでサポートされるfeatureのリストは以下のとおり(かっこ内はバージョン)。
hid
(Chrome 89)idle-detection
(Chrome 94)screen-wake-lock
(Chrome 84)serial
(Chrome 89)sync-xhr
(Chrome 65)web-share
(Chrome 86)その他情報
W3Cのリストにない以下のfeatureをどうすればいいか自分にはわからない。
speaker
vibrate
vr
#45427より
speaker
、vibrate
、vr
は#33439が最初に書かれた2018-07-25頃には"policy-controlled features"としてリストに掲載されていた。
しかしvibrate
はw3c/webappsec-permissions-policy@b7271acで削除され、vr
はw3c/webappsec-permissions-policy@bec5ce6でxr
に変更され、speaker
はw3c/webappsec-permissions-policy@18707d3で削除された(さらに言えばxr
はxr-spatial-tracking
に変更され、現在も実験的サポートのみとなっている)。
そこで、このコミットでこれらのpermission policyディレクティブを非推奨化する。
#46199より
つっつきボイス:「Feature-Policy
って何だろうと思ったら、Edgeガイドに記載されていました↓」「たしかWeb APIなどで利用を許可する機能を指定するときに使うヘッダーですね」
参考: §9.4 Feature-Policy Header -- Securing Rails Applications — Ruby on Rails Guides
「Railsだとこういうふうに書けるのか↓」
# Edgeガイドより
# config/initializers/permissions_policy.rb
Rails.application.config.permissions_policy do |policy|
policy.camera :none
policy.gyroscope :none
policy.microphone :none
policy.usb :none
policy.fullscreen :self
policy.payment :self, "https://secure.example.com"
end
「プルリクはこのW3Cの定義↓の更新に対応したんですね」「camera
とかmicrophone
とかusb
とかいろいろある」「お〜、なつかしのmidi
まであるとは」「Webでは見かけなくなったけど通信規格としては今も現役ですね」(しばらくMIDI談義)
参考: webappsec-permissions-policy/features.md at main · w3c/webappsec-permissions-policy
参考: MIDI - Wikipedia
🔗 エンジン内でダイレクトアップロードが利用できるようになった
動機/背景
このプルリクを作成した理由は、Railsエンジン内からのダイレクトアップロード呼び出しが使えないから。詳細
このプルリクは、アップロードURLをdata属性として追加すべきかどうかを決定するconvert_direct_upload_option_to_url
の条件を変更する。これにより、rails_direct_uploads_url
が存在するかどうかをmain_app
で検証するようになる。
この変更前は、エンジン内のテンプレートでこのメソッドを呼び出すとメインアプリのルーティングではなくエンジンのルーティングを探索していたため見つけられなかった。
テストはリグレッション防止用に追加した。
同PRより
つっつきボイス:「エンジンからダイレクトアップロードを呼べなかったのを修正したんですね」
参考: §11 ダイレクトアップロード -- Active Storage の概要 - Railsガイド
🔗 error_highlightの改良: ERBテンプレート内のエラー位置もハイライトするようになった
Finally landed this PR: https://t.co/tz2LzAeVCy
It depends on setting RubyVM.keep_script_lines (which saves raw source code to the iseq object after it's been evaluated). I think we could remove that though, but I need to do some work upstream 😩
— Aaron Patterson (@tenderlove) October 11, 2022
このプルリクは#45818に改良を加える。ERBテンプレート内で発生した例外の位置もハイライトするようになる。以下は改修前後のスクリーンショット。
改修前:改修後:
これを行うために、エラーハンドリングの詳細を変更して常にbacktrace locationsで扱うようにした。このプルリク前は、例外のラッパークラスで
backtrace_locations
を使う場合やbacktrace
を使う場合があった。ErrorHighlight
はbacktrace locationsオブジェクトでないと使えないので、コードをリファクタリングしてこれだけを使うようにした。このリファクタリングは残念ながら、
SyntaxError
例外の扱い方が原因で割としんどくなってしまった。SyntaxError
例外はバックトレースで構文エラーの位置情報を含んでいないので、バックトレースを改変することになる。SyntaxError
の振る舞いは維持する必要があるが、バックトレースの改変は筋が悪そうだったので、SyntaxError
のラッパーオブジェクトを導入してbacktrace
とbacktrace_locations
を実装した。次に困難だったのは、
ErrorHighlight
がException
オブジェクトとThread::Backtrace::Location
オブジェクトでしか動かないこと。上で導入したbacktrace locations オブジェクトがThread::Backtrace::Location
のインスタンスではないことは明らか。例外ラッパーのコードでis_a?
を書きたくなかったので、Thread::Backtrace::Location
にモンキーパッチを当てて、ErrorHighlight
の位置情報があれば返すようにした。これでSyntaxError
の場合に特殊な操作を行えるようになる(この時点ではそうなっていないが)。これでbacktrace locationsオブジェクトが実際に返されるようになり、ERBで
ErrorHighlight
が効くようになった。しかし表示されるのはテンプレートのソースコードではなくコンパイル済みERBのソースコードで、これは以下のような場合に位置が正しくならない。これに対応するため、メソッド名をテンプレートオブジェクトに対応付けるグローバルハッシュを1個ここに追加した。例外ラッパーがバックトレースを取得すると、メソッドが"テンプレート"メソッドかどうかをチェックして特殊なバックトレースオブジェクトを返す。この特殊なバックトレースオブジェクトは、単に
ErrorHighlight
のソースを実際のソースに対応付けるようテンプレートに指示する。このテンプレートオブジェクトは、その対応付けを行うようハンドラーに指示しているだけ。このハンドラーが実際のテンプレートストラテジー(ERBやHamlなど)になる。
ERB変換はここで行っている。ある種のハックではあるが、動いているようだ。
同PRより
つっつきボイス:「これだけ、Twitterで見つけた@tenderloveさんによる改修です」「@mameさんが実装したerror_highlight↓をさらに改良してERBテンプレート内のエラーにも対応したのか」「修正大変そう」「この改良もありがたいです🙏」
🔗Rails
🔗 WIP: RailsでLanguage Serverをサポート(Rails公式ニュースより)
Very much a WIP, but here is a lang server that refreshes the Rails app every time you save your buffer. It also communicates errors back to the editor pic.twitter.com/HXLRehYNXp
— Aaron Patterson (@tenderlove) September 23, 2022
つっつきボイス:「まだまだWIPですが、これも@tenderloveさんがRails用のLanguage ServerをRailsエンジンとして作っているところだそうです」「エンジン名はrefreshingか」「READMEにはまだFalconのthreadedモードでしか動かないと書かれているので、キャッシュのステート管理のような深い部分まで扱っていそう」
「Railsに慣れていない人ほどこういう機能があると助かるし、慣れている人の邪魔にもならないのでいいことしかないですね」「Language Serverはもっと普及して欲しいので、こういうのが登場するのはいいと思います👍」
参考: Official page for Language Server Protocol
🔗 Evil MartialsのViewComponent記事
In Part 1 of this thrilling series from Backend Engineer Alexander Baygeldin, he gives a high-level overview of GitHub’s ViewComponent library, how it offers a great approach for building modern frontends with Ruby on Rails—and why it deserves attention!https://t.co/OA5Cu4Sc3I
— Evil Martians (@evilmartians) October 12, 2022
つっつきボイス:「ちょっと長い記事です」「ViewComponent記事をよく見かけるようになってきた感じなので、ViewComponent好きな人が増えているのかも」「こういうサードパーティのコンポーネントフレームワークをサポートするようになったのはRails 6.1からなんですね(ウォッチ20200330)」「あくまでサードパーティによる拡張としてですけどね」
「前回のウォッチでも話しましたが(ウォッチ20221011)、ViewComponentのような機能はプレゼンテーション層をサーバーサイドで完結させるという意味ではRailsの正当な進化だと思っています」「サーバー側ですべてを掌握する感じですね」「自分は割と好きな方なんですが、現代のフロントエンドと方向が真逆で提案しづらい面もあったりはしますね」
「ところで記事でAMラジオのしくみの図が使われているのが懐かしい↓」「アンテナ、同調、検波、増幅でしたっけ」
参考: 受信機 - Wikipedia
🔗 JetBrainsの新しいIDE "Fleet"がpublic previewに
Announcing the public preview of @JetBrains_Fleet 🎉
Fleet is our new distributed polyglot editor and IDE built from the ground up using the IntelliJ Platform on the backend and a brand new UI and distributed architecture.
Learn more in the blog post.👇https://t.co/l9ZLE77ghj
— JetBrains (@jetbrains) October 12, 2022
つっつきボイス:「そうそう、Fleetがpublic previewになりましたね: JetBrains信者なので速攻動かしてみました」「軽量にするためにゼロから作り直したそうですが、どうでした?」「残念ながら今の時点ではめちゃめちゃクラッシュしますね」「あら〜」「ローカルファイルの編集は問題なくできますが、ssh接続だとプラグインのダウンロードのあたりで動かなくなりました: まあpublic previewはEAPよりも前の状態ですけどね」
参考: 早期アクセスプログラム (EAP)-JetBrains
「JetBrains IDEはこれまでJavaベースでしたけど、Fleetもそうですか?」「自分が見たエラーメッセージはJavaのエラーそのものでしたね」
「VSCodeをインストールするのが億劫な方なので、そのうちJetBrains Toolboxで管理できるFleetでやれるようになるといいなと思って期待しています: 今のままだとVSCodeにはまだまだ敵いませんが信者なので更新を待つつもり」
🔗 gemを使わないシンプルなPresenterパターン(Ruby Weeklyより)
つっつきボイス:「PresenterパターンもしくはDecoratorパターンをgemなしで書く記事: モジュールで書けばいいのではと思ったら案の定concernsで書いてますね」
# 同記事より
# app/models/concerns/presentable.rb
module Presentable
def decorate
"#{self.class}Presenter".constantize.new(self)
end
end
# 同記事より
# app/models/user.rb
class User < ApplicationRecord
include Presentable
# ...
end
# 同記事より
# app/presenters/user_presenter.rb
class UserPresenter < SimpleDelegator
include ActionView::Helpers::TextHelper
def unread_notifications_text
unread_count = notifications.unread.count
if unread_count == 0
return "You don't have unread notifications."
end
"You have %{unread_count} unread %{pluralize(unread_count, 'notification')}".
end
end
参考: class SimpleDelegator
(Ruby 3.1 リファレンスマニュアル)
「MVCの初期の頃から使われている伝統的なDecoratorの書き方ですね: 10年前ぐらいにこういう記事をよく見かけました」「なるほど」「今はDecorator的なことはフロントエンドやビュー寄りのところでやることが多いかな」「今だと他の方法がいろいろありそうですね」「モデルにDecoratorを付与する方法は、個人的にはちょっと自由度が高すぎるというかモデルとあまり分離されていなくて強すぎる感じもしますが、こういう記事で伝統的な書き方を知っておくのもよいと思います👍」
前編は以上です。
バックナンバー(2022年度第4四半期)
週刊Railsウォッチ: RailsとPostgreSQLで列挙型を作成する6つの方法、Ubuntu Proほか(20221012後編)
- 20221011前編 Turbo 7.2.0リリース、GitLabのDevSecOpsサーベイ結果ほか
- 20221004後編 ヒアドキュメント拡張の提案、『組織に自動テストを根付かせる戦略』ほか
- 20221003前編 Kaigi on Rails 2022のタイムテーブル発表、書籍『Practicing Rails』ほか
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。
週刊Railsウォッチについて
TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)