Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

週刊Railsウォッチ: ShopifyのWebAssemblyツールチェインRuvyほか(20231025後編)

こんにちは、hachi8833です。

週刊Railsウォッチについて

  • 各記事冒頭には🔗でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
  • お気づきの点がありましたら@hachi8833までメンションをいただければ確認・対応いたします🙏

TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)

🔗Rails

🔗 ActiveSupport::OrderedOptions#dig!の提案(現在オープン)


つっつきボイス:「ついさっき(注: つっつきが行われた10/19夕方)神速さんがこのプルリクを投げていたのをruby-jp Slackで見かけました: fetchをチェインしなくてもこうやってdigで書けるんですね」

# Before
Rails.application.credentials.fetch(:aws).fetch(:access_key_id)
Rails.application.config_for(:example).fetch(:foo).fetch(:bar)
# After
Rails.application.credentials.dig!(:aws, :access_key_id)
Rails.application.config_for(:example).dig!(:foo, :bar)

「ほほ〜、digは前からRubyにもRailsにもあるけど、ここで提案されているのは!付きのdig!だから、指定したキーが存在しなかった場合にエラーをraiseするということか」「なるほど」「たしかfetchはキーが存在しなければエラーをraiseするけど、今のdigはそうなっていないからdig!を提案しているんですね: これはたしかにあっていいメソッド👍」

# activesupport/lib/active_support/ordered_options.rb#L53
    def dig!(*keys)
      keys.flatten.inject(self) do |h, key|
        h[key.to_sym].presence || raise(KeyError.new(":#{key} is blank"))
      end
    end

参考: Hash#dig (Ruby 3.2 リファレンスマニュアル)
参考: Rails API dig -- ActiveSupport::OrderedOptions
参考: Hash#fetch (Ruby 3.2 リファレンスマニュアル)

「Ruby本家でも以前からdig!が提案されているそうです↓」「たしかにRuby本体にもあっても全然いいメソッドですね」

参考: Feature #14602: Version of dig that raises error if a key is not present - Ruby master - Ruby Issue Tracking System -- 現在オープン

「ところでRubyのハッシュのキーを厳密に扱おうとすると厄介な点があるんですよ: ハッシュのキーにアクセスしてnilが返ってきたら"そのキーは存在していない"と解釈するのが普通ではあるんですが、実は"そのキーの値がnilである"可能性もある」「あ〜、それ怖いヤツだ」「digの場合は、nilが返ってきたときに"キーが存在しない"と解釈するか"キーの値がnilである"と解釈するかが、ともすると曖昧になることがあるんですよ」「う〜む」「そこを厳密に判定するなら、キーが存在しなければ確実にエラーをraiseするdig!が欲しくなるでしょうね」「やっぱりnil値怖い...」

🔗 マイルストーンから: Rack::Sendfile削除の提案と、フォームのremotelocalオプション廃止の提案


つっつきボイス:「RailsのGitHubリポジトリにマイルストーンが2つできていたので、そこから2つ取り上げてみました」

参考: 7.1.2 Milestone
参考: 7.2.0 Milestone

「1つ目は7.2.0マイルストーンにあった、Rack::Sendfileミドルウェアをデフォルトで削除してダミーのFakeSendfileに置き換えようというプルリクです: send_fileで使われるRack::Sendfileが、リバースプロキシなしだとセキュリティ的にあまりよろしくないという話が以前から指摘されているので、それに関連しているようです」「あらま」「以下の記事でもRack::Sendfileは使わないなら外しておこうと書かれていますね↓」

参考: RailsでRack::Sendfileを使っていない場合は外しておいた方が良いという話


「2つ目も7.2.0マイルストーンにあったもので、form_forform_withremoteオプションやlocalオプションの扱いを修正しようというプルリクです」「2年前のプルリクだけど、これ修正したくなるのわかる!: どっちのオプションがどう効くのかわからなくなること多すぎ」「ほんとそうですよね」「form_forremoteだったのがform_withlocalに変わったんでしたっけ?」「えっと、そのはずです」

Rails 5.1〜7.1: 'form_with' APIドキュメント(翻訳)

「上のform_with APIドキュメント翻訳を更新したときも、localオプションの説明がよくわからなくてさんざん確認したのを思い出しました↓」「実際に動かさないと確信が持てないレベル」


同記事より

form_forは禁止ではないけど、とっくに非推奨なんだから、form_withだけ使いやすくなってくれればそれでいいと思うんですけどね」「どんな形になるかわからないけど、よくなって欲しいです🙏」

🔗 Rails 7.1で生成されるDockerfile


つっつきボイス:「Rails 7.1でrails newするとproduction用のDockerfileも生成されるようになったんですが、そのあたりを試してみた記事です」「お〜、今どきのRailsはDockerで動くのがもう当たり前になってきてるので、Dockerfileの設定を考えなくて済むのはありがたい」「自分でも試したんですが、生成されるDockerfileには、rails newに渡したオプションに応じてPostgreSQLやSQLite3の関連ファイルも自動追加してくれていて、Dockerのマルチステージビルドも取り入れられています」「いいですね〜👍」

# SQLite3の場合
# Install packages needed for deployment
RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y curl libsqlite3-0 libvips && \
    rm -rf /var/lib/apt/lists /var/cache/apt/archives
# PostgreSQLの場合
# Install packages needed for deployment
RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y curl libvips postgresql-client && \
    rm -rf /var/lib/apt/lists /var/cache/apt/archives

参考: マルチステージ ビルドを使う — Docker-docs-ja 24.0 ドキュメント

「自分でもRails 7.1アプリをrender.comにデプロイしてみたところ、無改造のDockerfileがそのままストンと使われました」「なるほど」「記事でもRails 7.1を例のkamal(旧MRSK)でデプロイした例を紹介していますけど、Rails 7.1のDockerfileはkamalでの利用を意識しているようです: ちなみにkamalはssh接続さえつながればクラウドの種類やベアメタルを問わずDockerベースのプロジェクトをデプロイできるそうです」

参考: Cloud Application Hosting for Developers | Render

Kamal README: 37signalsの多機能コンテナデプロイツール(翻訳)

🔗 TLDR: 速度重視の?minitest風テスティングフレームワーク(Ruby Weeklyより)


つっつきボイス:「この間Railsコミッターの@tenderloveさんとtestdoubleの@sealsさんが発表していた高速なテスティングフレームワークだそうです」「"遅いテストを待っていられない人のためのフレームワーク"ですか」「TLDRって?」「"長すぎるから読んでない"(too long; didn't read)という人向けの要約を表す、英語圏でよく使われる略語ですね」「昔なつかし今北産業みたいなヤツですか」「同じこと思った」

参考: tldrの意味・使い方|英辞郎 on the WEB

tendersearls/tldr - GitHub


同リポジトリより

「デフォルトでパラレルに動作するんですって」「minitestとほぼ互換とあるので、minitestとは別物ということかな」「直近で変更されたファイルを最初にテストするのね」

「最初はジョークだったけど本当に作ってみたということみたい」「んん、よく見ると"1.8秒経過したらテストの実行を止める"...だと?」「やっぱりジョークだった😆」「そりゃ速いわ😆」


なお、元記事の趣旨は「全部のテストをたまに実行するより、小さなテストを頻繁に実行する方が効果的である」「テストが1.8秒で強制的に打ち切られれば無意味なテストを削除するモチベにもつながるだろう」という、ジョークとも本気ともつかない味わいに満ちています。

🔗 Rails 7.1でテスト失敗のデフォルト出力が変わっていた話(Ruby on Rails Discussionsより)


つっつきボイス:「これは自分がたまたま見つけたもので、コントローラのテストが失敗したときの振る舞いがRails 7.0と7.1で違っていることに気づきました↓」「今まではActionNotFoundがraiseされてたのに、404 Not Foundに変わっちゃったのね」

# Rails 7.0の場合
$ bin/rails test
...
StaticPagesControllerTest#test_should_get_about:
AbstractController::ActionNotFound: The action 'about' could not be found for StaticPagesController
    test/controllers/static_pages_controller_test.rb:16:in `block in <class:StaticPagesControllerTest>'
...
# Rails 7.1の場合
$ rails test
...
  1) Failure:
StaticPagesControllerTest#test_should_get_about [/Users/hachi8833/deve/yasslab/environment/sample_app/test/controllers/static_pages_controller_test.rb:17]:
Expected response to be a <2XX: success>, but was a <404: Not Found>

「それで上のdiscuss.rubyonrails.orgで質問したところ、以下のコンフィグが7.1で変わったためではないかと教えていただきました(#45867): 設定を:noneに変更したら従来と同じ振る舞いに戻りました」

# 7.0まではtrueかfalseを設定できる
config.action_dispatch.show_exceptions = false # デフォルト

# 7.1では:all、:rescuable、:noneを設定できる
config.action_dispatch.show_exceptions = :rescuable # デフォルト

参考: §3.5.9 ActionDispatch::ShowExceptions -- Rails アプリケーションの設定項目 - Railsガイド

🔗Ruby

🔗 Ruvy: ShopifyによるRuby用WebAssemblyツールチェイン

Shopify/ruvy - GitHub


つっつきボイス:「Shopifyがまた新しいものをリリースしました」「RubyコードとRuby VMをWasmにビルドできるのか!」「まだ始まったばかりみたいですが、Shopifyの実装力と実績からするとそう遠くないうちに仕上がるかも」「ちょうどこういう記事も出ていますし↓、WebAssembly周りがだんだん加速されている気がします」

参考: VSCodeがWebAssemblyの実行時デバッグに対応。C/C++やRust、Zigなどのソースコードと関連付け、変数参照、ブレークポイントなど可能に - Publickey


つっつき後に以下の記事も公開されていました↓。同記事で、ShopifyがJavyというJavaScriptをWasmにするツールチェインも2月に出していたことを今頃知りました。

参考: より高速なRubyのWebAssembly実装「Ruvy」、Shopifyがオープンソースで公開。Ruby仮想マシンとRubyアプリを組み合わせてビルド - Publickey

参考: Bringing Javascript to WebAssembly for Shopify Functions (2023)

bytecodealliance/javy - GitHub

🔗 その他Ruby


つっつきボイス:「1件目は、マネーフォワードが主催するRubyKaigi 2023の振り返りイベントで、RubyKaigiに参加した人や来年沖縄で開催されるRubyKaigi 2024に関心のある人に加えて、スポンサー企業やスポンサーを検討中の企業の技術広報や採用担当者にもよさそうです」

「2件目はRuby AIというTwitterコミュニティです」「RubyをAIで書くのかな、それともRubyでAIを書くのかな?」「どっちだろう...どちらの話題もいけそうな気がします、たぶん😅」


A community for folks interested in learning about and building AI applications in Ruby
Community Descriptionより

🔗CSS/HTML/フロントエンド/テスト/デザイン

🔗 Tailwind CSSがカオスにならないためのベストプラクティス5つ(Ruby Weeklyより)


つっつきボイス:「個人的にTailwind CSSが好きなんですが、Evil Martiansが使いこなしのコツを記事にまとめてくれていて、近々翻訳記事を出します(しばらくTailwind話)」

参考: Tailwind CSS - Rapidly build modern websites without ever leaving your HTML.

「Tailwindは使ったことないけど、CSSを別ファイルに書くというのが好きでないので、定義済みのCSSクラスをHTMLのclass属性に書けるとか、CSSクラスの名前を考えなくていいみたいなのはちょっとよさそうですね」「記事によると、専門のデザイナーが作ったデザインシステムが何らかの形でプロジェクトで確立されていることと、いわゆるコンポーネント(ViewComponentやPhrexなど)がプロジェクトに導入済みであることがTailwind CSS導入に欠かせない要件だそうです」

参考: デザインシステムとは?|国内外の参考になる事例10選と共に解説|セブンデックス


つっつき後に以下のツイートを見つけました。Rails WorldでもTailwind CSSのトピックが登場していたんですね。


後編は以上です。

バックナンバー(2023年度第4四半期)

週刊Railsウォッチ: 7.1アップグレードガイドにActive Record暗号化設定の注意事項が追加ほか(20231024前編)

ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。

Ruby Weekly

Ruby on Rails Discussions


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。