- Ruby / Rails関連
週刊Railsウォッチ: Rails 7がRuby 3.1のClass#descendantsに対応、GitHub Issue風ファイルアップローダほか(20211115前編)
こんにちは、hachi8833です。つっつきの後でこの番組見ました↓。
IIJでは何年かに一度「データセンターの中を撮影したい」と相談を受けています。ただ、今回の番組のように「ケーブルの配線美を撮影したい」というお話は初めてでした。
IIJ&ネットチャート撮影協力
NHK BS1「ケーブルアート~あなたの知らない美の世界~」 本日 22:40~22:50https://t.co/q1eByHiVuP pic.twitter.com/9ViXdmTTPs— 堂前@IIJ (@IIJ_doumae) November 11, 2021
お知らせ
来週の週刊Railsウォッチは祝日のためお休みをいただきます🙇。
🔗Rails: 先週の改修(Rails公式ニュースより)
更新情報にまた追い抜かれ中...ハロウィンエディションの残りと次の更新情報から見繕いました。
- 更新情報: 🎃 Halloween Edition: Zeitwerk migration guide, selenium-webdriver, and some Ruby 3.1 snacks | Riding Rails
- 更新情報: Nested attributes for delegated types, improved performances and more! | Riding Rails
🔗 uuid_namespace
のパラメータが未定義文字列の場合のUUID生成を修正
Digest::UUID
で定義されているのと異なるnamespace IDの場合のDigest::UUID.uuid_from_hash
の振る舞いを修正した。
新しい振る舞いは、コンフィグのconfig.active_support.use_rfc4122_namespaced_uuids
オプションをtrue
に設定すると有効になる(新規アプリではこれがデフォルト)。
アップグレードしたアプリでは古い振る舞いがデフォルトになり、Digest::UUID
でnamespace IDとして定義されている定数と異なる場合に毎回deprecation warningを出力する。
Alex Robbin, Erich Soares Machado, Eugene Kenny
同Changelogより
つっつきボイス:「Digest::UUID
ってあるんですね」「UUIDの名前空間とは...?ググってみるとPythonライブラリのドキュメントが出てきた↓」「これは知らなかった」「コードのDNS_NAMESPACE
やURL_NAMESPACE
などもこのドキュメントに載っているので、UUIDには名前空間の仕様もあるということなのか、へ〜!」
参考: uuid --- RFC 4122 に基づくUUID オブジェクト — Python 3.10.0b2 ドキュメント
# activesupport/lib/active_support/core_ext/digest/uuid.rb#58
+ def self.pack_uuid_namespace(namespace)
+ if [DNS_NAMESPACE, OID_NAMESPACE, URL_NAMESPACE, X500_NAMESPACE].include?(namespace)
+ namespace
+ elsif use_rfc4122_namespaced_uuids == true
+ match_data = namespace.match(/\A(\h{8})-(\h{4})-(\h{4})-(\h{4})-(\h{4})(\h{8})\z/)
+
+ raise ArgumentError, "Only UUIDs are valid namespace identifiers" unless match_data.present?
+
+ match_data.captures.map { |s| s.to_i(16) }.pack("NnnnnN")
+ else
+ ActiveSupport::Deprecation.warn <<~WARNING.squish
+ Providing a namespace ID that is not one of the constants defined on Digest::UUID generates an incorrect UUID value according to RFC 4122.
+ To enable the correct behavior, set the Rails.application.config.active_support.use_rfc4122_namespaced_uuids configuration option to true.
+ WARNING
+
+ namespace
+ end
+ end
参考: Rails API Digest::UUID
🔗 Ruby 3.1のClass#descendants
に対応
Ref: https://bugs.ruby-lang.org/issues/14394
Ref: ruby/ruby#4974
ObjectSpaceをイテレーションする必要のないClass#descendants
のネイティブ実装がRuby 3.1に入る公算が高いので、可能ならこれを使うべき。
Rubyのプルリクがマージされるのを待ってからこちらをマージするつもり。DescendantsTracker
のほとんどをスキップする必要もあるが、検出方法がまだわからないので、利用可能かどうかをRUBY_VERSION
でチェックする方法で回避した。
# activesupport/lib/active_support/core_ext/class/subclasses.rb#L17
def descendants
ObjectSpace.each_object(singleton_class).reject do |k|
k.singleton_class? || k == self
end
- end
+ end unless method_defined?(:descendants) # RUBY_VERSION >= "3.1"
つっつきボイス:「ActiveSupport::DescendantsTracker
にあるdescendants
メソッドが、Ruby 3.1にネイティブのClass#descendants
が入ったのを機にRubyのバージョンを見て切り替えるようにしたんですね」「Active SupportにあるメソッドがこうやってRuby本家に取り入れられることはときどきありますよね」「descendants
もとうとう出世メソッドになった」「出世おめでとうございます🎉」
- Rails API:
ActiveSupport::DescendantsTracker
-
PR: Add Class#descendants by jeremyevans · Pull Request #4974 · ruby/ruby
🔗 テストごとにExecutor#wrap
を呼び出すオプションが追加
Rails.application.executor
フックがすべてのテストの前後で呼ばれるようになった。
これにより、リクエストやジョブのローカルなステートがリセットされるのを適切にシミュレートするようになり、テストとテストの間でステートが漏れるのを防止できる。
ただし、test環境で実行されるexecutor
フックはリエントラントであることが求められる。
Jean Boussier
同Changelogより
つっつきボイス:「変更が割と多いかも」「テスト間でステートが漏れ出さないようにする改修: active_support.executor_around_test_case = true
というコンフィグで設定できるのね」
🔗 date_select
ヘルパーにday_format
が追加
:year_format
オプションと同様の:day_format
オプションをdate_select
に追加。
ロケールをja(日本語)にしたRailsアプリケーションとrails-i18nではdate_select
で以下が表示される。
日本では2021-10-29
という日付を2021年10月29日
と表示するのが普通(年はyear、月はmonth、日はdayの意味)。
しかし現在のdate_select
にはdayの書式をカスタマイズするオプションがないのでday_format
を追加した。
form.date_select :published_date, year_format: ->(year) { "#{year}年" }, day_format: ->(day) { "#{day}日" }
form.date_select :published_date, order: %i[day month year], day_format: ->(day) { day.ordinalize }
つっつきボイス:「お〜なるほど、今までyear_format
は指定できたけどday_format
はできなかったのをできるようにしたんですね」「最近RailsでAPIとバッチを書くことが多くてビューを書く機会があまりなかったけど、今までできなかったのか〜」「month_format
がないと思ったらmonth_format_string
があった」
🔗 delegated_type
でaccepts_nested_attributes_for
をサポート
このプルリクは、
delegated_type
にaccepts_nested_attributes_for
のサポートを追加する。これで以下のようなメソッドを書かずにレコードを手軽に作成や更新できるようになる。
class Entry < ApplicationRecord
delegated_type :entryable, types: %w[ Message Comment ]
def self.create_with_comment(content, creator: Current.user)
create! entryable: Comment.new(content: content), creator: creator
end
end
accepts_nested_attributes_for
が使えると以下のように書ける。
class Entry < ApplicationRecord
delegated_type :entryable, types: %w[ Message Comment ]
accepts_nested_attributes_for :entryable
end
params = { entry: { entryable_type: 'Comment', entryable_attributes: { content: 'Smiling' } } }
entry = Entry.create(params[:entry])
作った理由
accepts_nested_attributes_for
によるネステッドフォームは非常に強力。これはDelegated Typeでも使えるようにするために足りなかった最後のピースとなる。
疑問
これはポリモーフィックなbelongs_to
リレーションシップなので、他にどんなテストがあるとよいだろうか?(TestNestedAttributesOnABelongsToAssociation
で既にテストされているので)
同PRより
つっつきボイス:「Delegated Typeといえば以前話題になりましたね(ウォッチ20200601)」「Delegated Typeでaccepts_nested_attributes_for
が使えるようになったのね: 自分はaccepts_nested_attributes_for
は使わないけど」「このメソッドで苦しんだ人を割とよく見かける印象あります」「Rails wayなフォームですべてできるならいいんですが、そこからはみ出したときにちょっとね...」
参考 【Rails】accepts_nested_attributes_forを使用しない方が良いワケとその代替方法
「そういえばDelegated TypeのAPIドキュメント↓を翻訳したので近々公開しようと思います」
- Rails API:
ActiveRecord::DelegatedType
🔗Rails
🔗 StimulusとActive StorageでGitHub Issue風のファイルアップローダを作る(Ruby Weeklyより)
つっつきボイス:「これはたしかにGitHub issue風↓」「こんなふうに作れるんですね、いいな〜」
「今日ちょうど社内勉強会で話題になりましたけど、Active Storageはダイレクトアップロードにも対応していますね」「そうそう、意外に知られてないのかも」「サーバーに負担をかけずにクラウドにアップロードできるダイレクトアップロード機能はあってうれしい機能ですね: 要するにでかいファイルをサーバーで受け取りたくない」「ほんとに」
参考: 9 ダイレクトアップロード -- Active Storage の概要 - Railsガイド
🔗 minitest-spec-rails(Ruby Weeklyより)
何だか懐かしい風味のロゴと東洋風フォントですね↓。
つっつきボイス:「minitestでspecが使いたいのかな?」「普通にminitestで書けばよさそうですけどね」
「お、ActiveSupport::TestCase
を使いながらMiniTest::Spec::DSL
にあるit
でも書けるのね↓」「なるほど」「ActiveSupport::TestCase
だけどRSpec風にit
でも書きたい人向けという感じかな」
# 同リポジトリより
require 'test_helper'
class UserTest < ActiveSupport::TestCase
let(:user_ken) { User.create! :email => 'ken@metaskills.net' }
it 'works' do
user_ken.must_be_instance_of User
end
end
「ActiveSupport::TestCase
を継承しないとテスト用拡張モジュールを使えないようなgemは、実は割とあるんですよ」「あ〜」「ズバリRailsがそうだったりします」「そういえばRailsフレームワークのテストコードはRSpecじゃないんですよね」「minitestですね」
参考: library minitest/unit (Ruby 3.0.0 リファレンスマニュアル)
🔗 Railsコアメンバーによるプルリクレビュー実況動画
つっつきボイス:「ruby-jp SlackのEnglishチャンネルで見かけた、RailsコアメンバーのKasperさんがRailsフレームワークへのプルリクをレビューする様子の実況中継です」「お〜、RubyKaigiなどでやりそうな企画ですね: ヒアリングの練習がてら見てみるといいかも」
🔗 その他Rails
つっつきボイス:「そうそう、@koicさんが11/19(金)の銀座Rails#39の招待講演枠に登壇されます: まだ一般の発表枠はあるので皆さんぜひお気軽に応募お願いします↓」
【誤植修正版】11/19(金)19:00より銀座Rails#39 をZoomオンライン開催予定(要事前登録)です。今回の招待講演枠は伊藤浩一(@koic)さん。一般登壇者募集も行っておりますので発表の場を探している方はぜひご検討下さい。詳細はConnpassサイトにて! https://t.co/Gg4L5Scuok
— 銀座Rails (@GinzaRails) November 1, 2021
前編は以上です。
バックナンバー(2021年度第4四半期)
週刊Railsウォッチ: JSON.parseの機能、Opal 1.3、async gem、Linuxコマンドチートシートほか(20211110後編)
- 20211102後編 2021年度Rubyアソシエーション開発助成、Rails REST APIレベルで楽観的ロックほか
- 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ウォッチタグ)