- Ruby / Rails関連
週刊Railsウォッチ: 7.1でバリデーションメッセージのアポストロフィ->カーリー置き換えが取り消しほか(20230928後編)
こんにちは、hachi8833です。つっつきで一同がこのコードにどよめきました。
FizzBuzz 実装はいろいろあるけど、 kazuho さんによる実装は奇妙さと美しさが同居していて今でも強く印象に残っているhttps://t.co/f208DBeRUI pic.twitter.com/G3QoReGdyw
— Takuto Wada (@t_wada) September 21, 2023
🔗Rails
🔗 Railsのミドルウェアで知っておくべき(ほぼ)すべてのこと(Ruby Weeklyより)
つっつきボイス:「Railsを支えているRackミドルウェアの解説記事です」「Rackとミドルウェアはずっと前からこういう仕組みですね: 他にもいろいろ記事がありますし、このあたりは知っておいて損はない👍」
🔗 スクリーンキャスト: Rails 7.1の機能で認証をゼロから構築する(Ruby Weeklyより)
つっつきボイス:「5:15のあたりで、RailsのCurrentAttributes
を継承したCurrent
クラスを作って実装している」
参考: § 1.12 SecurePasswordモジュール -- Active Model の基礎 - Railsガイド
参考: Rails API ActiveSupport::CurrentAttributes
「ここでは任意の場所からログイン中のユーザー情報を取得できるようにするためにCurrentAttributes
を使っているんですね: こうすると引数渡しとかを経由せずに任意の場所(モデルやヘルパーも含む)からグローバルコンテキストとして呼び出すことができるので、使いようによっては便利です」「なるほど」
「ただし、任意の場所から呼び出せるグローバルなコンテキストにメソッドの振る舞いが依存してしまうと、ユニットテスト時にも都度考慮してMockしてあげる必要があるなど副作用を生みやすいので、最近はあまり見ない実装方法かもしれませんね(昔はこういうフレームワークも結構ありましたが)」
「このスクリーンキャストに関連している7.1のプルリクを貼っておきました」「has_secure_password
はRails標準の機能ですね」「7.1ではパスワードチャレンジの機能なども追加されているのね」
参考: Enhance has_secure_password to also generate a password_salt method by lazaronixon · Pull Request #47490 · rails/rails
参考: Add authenticate_by when using has_secure_password by jonathanhefner · Pull Request #43765 · rails/rails
参考: Add ActiveRecord::Base::generates_token_for
by jonathanhefner · Pull Request #44189 · rails/rails
参考: Add ActiveRecord::Base::normalizes
by jonathanhefner · Pull Request #43945 · rails/rails
参考: Support password challenge via has_secure_password
by jonathanhefner · Pull Request #43688 · rails/rails
🔗 Brotli圧縮でRailsのキャッシュ効率を改善(Ruby Weeklyより)
つっつきボイス:「Brotliって圧縮アルゴリズムなんですね」「Brotliのリポジトリを見ると、LZ77アルゴリズムのバリアントなのね: rails-brotli-cache gemを使ってRailsのキャッシュアルゴリズムをGzipからこのBrotliに差し替えて圧縮率を高めたという記事ですね」
# 同記事より
require 'json'
require 'brotli'
json = File.read("sample.json")
puts json.size # => 1127380 bytes ~ 1127kb
brotlied = ::Brotli.deflate(json, quality: 6)
puts brotlied.size # => 145056 bytes ~ 145kb
参考: Brotli - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN
参考: LZ77 - Wikipedia
🔗 feature specをsystem specで書き直す(Ruby Weeklyより)
# 同記事より
# OLD: feature spec type
RSpec.feature "name", type: :feature do
# NEW: system spec type
RSpec.describe "name", type: :system do
つっつきボイス:「RSpecのfeature specを頑張って書き直した記事だそうです」「今はCPUリソースが豊富になったのでsystem specもやりやすくなりましたね」「そういえばfeature specがRSpecの標準でなくなって随分経ってる」「記事によると、RSpec 3.7で"今後はsystem specを使ってね"とアナウンスされていたそうです↓」「Rails本体はもっと前からシステムテストが主流ですね」
参考: RSpec 3.7 has been released!
参考: § 6 システムテスト -- Rails テスティングガイド - Railsガイド
🔗 Rails 7.1.0の「バリデーションメッセージのアポストロフィをカーリーに置き換える」プルリク(その後取り消し)
元記事: Rails v7.1.0 で can't be blank
が can’t be blank
に変わる - アジャイルSEの憂鬱
つっつきボイス:「Rails 7.1.0beta1のChangelogを読んでて自分も気になっていましたが、神速さんが早速記事にしていました」「これね〜、日本語圏だと'
と’
を意識して使い分けないことが多いので、従来のメッセージを想定して手打ちしたテストが失敗したときに原因がすぐにわからない、なんてことになりそうだし、ちょっとどうかなという気持ち」「英語圏の人はいいのかもしれないけど」「実際、英語圏ではストレートの""
や''
はあくまで間に合わせで、カーリーの“”
や‘’
の方が正式という意識があるんですよね」
参考: Improve typography of user facing validation messages by jdufresne · Pull Request #45463 · rails/rails
参考: 引用符 - Wikipedia
「ドキュメントでのカーリー置き換えはともかく、デフォルトのバリデーションメッセージ↓については、i18nで定義されているデフォルトのen.ymlの内容を上書きする設定を組み込めば元の挙動に戻せると思いますけどね」「#45463に反論も寄せられているし、取り消しになってくれるといいんですけどね」
# activemodel/lib/active_model/locale/en.yml#L10
inclusion: "is not included in the list"
exclusion: "is reserved"
invalid: "is invalid"
- confirmation: "doesn't match %{attribute}"
+ confirmation: "doesn’t match %{attribute}"
accepted: "must be accepted"
- empty: "can't be empty"
- blank: "can't be blank"
+ empty: "can’t be empty"
+ blank: "can’t be blank"
present: "must be blank"
なお、この種の変更は英語でよく"cosmetic change"と呼ばれます。本質的でない変更というニュアンスもあります。
つっつきの後、昨日#45463が取り消されました↓。昨日リリースされたv7.1.0.rc1に反映されています🎉。
参考: Revert typography change in user facing errors · rails/rails@acfa045
🔗Ruby
🔗 YJITベンチマーク対象にLobste.rsのソースコードも追加(Ruby Weeklyより)
つっつきボイス:「Lobste.rsは実際に動いているSNSサイトだそうです」「Lobste.rsってロブスターなのね」「.rsで一瞬Rustの拡張子かと思った」
参考: Lobsters
「このソースコードがベンチマークに追加されたんですね↓」
参考: yjit-bench/benchmarks/lobsters at main · Shopify/yjit-bench
🔗 Rubyの行カウントの効率改善(Ruby Weeklyより)
つっつきボイス:「記事によると、str.count($/)
と書くとstr.lines.count
より1.5倍速いんだそうです」「何この書き方?」「見たことない」「メモリアロケーションも減るんですって」「Cの内部実装を利用しているらしいけど、正規表現...じゃないのかな?」「Cのコードを読むしかないか」
# 同記事より
Warming up --------------------------------------
size 31.000 i/100ms
length 75.000 i/100ms
count 77.000 i/100ms
each_line + count 81.000 i/100ms
count($/) 196.000 i/100ms
Calculating -------------------------------------
size 1.529k (±33.9%) i/s - 4.774k in 5.015361s
length 1.434k (±38.8%) i/s - 5.025k in 5.139834s
count 1.335k (±40.7%) i/s - 4.697k in 5.079353s
each_line + count 1.411k (±39.5%) i/s - 5.022k in 5.110146s
count($/) 2.231k (± 2.6%) i/s - 11.172k in 5.012323s
Comparison:
count($/): 2230.5 i/s
size: 1529.0 i/s - 1.46x (± 0.00) slower
length: 1434.2 i/s - 1.56x (± 0.00) slower
each_line + count: 1411.0 i/s - 1.58x (± 0.00) slower
count: 1334.9 i/s - 1.67x (± 0.00) slower
参考: String#count
(Ruby 3.2 リファレンスマニュアル)
🔗 re2: Google正規表現エンジンのRubyラッパー(Ruby Weeklyより)
つっつきボイス:「re2はバックトラック機能がない代わりに高速でReDoS脆弱性が発生しないという特徴があります」「re2 gemは、Googleの正規表現エンジンであるre2のラッパーなのね」
「このre2を見て、以下の記事で言及されているのを思い出しました↓」「Rubyのメイン正規表現エンジンをOnigmoからre2に変える試みがあったんですね」「Onigmo正規表現エンジンはRegexp以外でもStringなどあちこちで使われているので、たしかに差し替えは難しそう」
shyouhei:(Rubyで)RE2を使ってみようという話を実は前に言ってた人がいて、誰だっけな。Sam Saffronかなぁ。Sam SaffronはDiscourseを作っている人ですけど、ともかく正規表現が遅いのは困るから早くしてくれみたいな感じで、早い正規表現エンジンがここにあるじゃん、これ使えばいいじゃんみたいな話をして。それでさっき話が出ていた遠藤さんが実際ちょっとやってみようかなぁみたいな感じでちょっとだけ手を出して、生半可な気持ちでは手が出せませんねということが明らかになって撤退していった感じですね。
(中略)
shyouhei:Rubyの言語の処理系の中から今のRubyの正規表現エンジンを抜くっていう話になると、多言語対応(M17N)が超大変。Rubyの成立過程として先に正規表現の方が多言語対応して、そこに後からRuby本体が乗ったので、正規表現の方だけ抜こうと思うとちょっとテクニカルに大変ですね。
同記事より
「Go言語の標準の正規表現ライブラリであるregexpパッケージでもre2が使われていて、以前はバックトラックできないのが貧弱に思えたので使わなかったんですが、今思えば速度とセキュリティを優先していたのかもしれない」
参考: regexp package - regexp - Go Packages
🔗 その他Ruby
タイムテーブル見に行ったついでにリンクぶら下げておきます🐼🐼https://t.co/9afQLIYqj9 pic.twitter.com/NSJeVouy88
— shokola (@shokolateday) September 20, 2023
つっつきボイス:「大江戸Ruby会議10が浅草で開催決定🎉」「アフターパーティの会場は浅草花やしきですって」「会場は現在手配中だそうです」「花やしきって貸し切りサービスやってるんですね」
🔗DB
🔗 PostgreSQL 16がリリース
News: PostgreSQL 16 Released! https://t.co/9c9lgBEueq
— PostgreSQL (@PostgreSQL) September 14, 2023
つっつきボイス:「BPS社内Slackに貼っていただいた記事です」「そうそう、まだ詳しく見てないけど新機能の中ではLogical replicationがとりあえず気になっているかな: Row Filters Ruleというものを使うと、特定の条件に一致するデータだけを論理レプリケーション可能になるみたいですね」「なるほど」「従来でも論理レプリケーションするgemが使えたけど、標準機能でできるのはいいですね👍」
参考: PostgreSQL: Documentation: 16: 31.3. Row Filters
参考: 第31章 論理レプリケーション
🔗 PostgreSQLに保存した大量のBase64文字列データを移行した話(Ruby Weeklyより)
- 元記事: We used to store files as base64 strings in Postgres, but not anymore | The Official MailPace Blog
つっつきボイス:「メールの添付ファイルをBase64文字列でデータベースに保存してたらものすごく大きくなった、あるある」「PostgreSQLにバイナリで保存すればもう少しましだったかもしれないけど、そもそもこの種のデータをデータベースに保存することが減っていますね」「今はファイルがめちゃくちゃ大きくなってますしね」「記事ではActive JobとActive Storageを使ってデータをRailsのオブジェクトストアに移動したのね」
# 同記事より
class SaveAttachmentsToCellarJob < ApplicationJob
queue_as :default
def perform(email_id)
email = OutgoingEmail.find(email_id)
email.attachments.each do |attachment|
next if attachment.content == nil # Skip if already moved
decoded_content = Base64.decode64(attachment.content)
# We use at tempfile here to avoid using memory for large attachments
file = Tempfile.new
file.binmode
file.write(decoded_content)
file.rewind
attachment.file.attach(io: file, filename: attachment.name,
content_type: attachment.content_type, identify: false) # This is what stores the file in the object store, we set identify to false as the users provide teh Content-Type themselves
attachment.update(content: nil) # Remove the base64 string from the database
end
end
end
🔗JavaScript
🔗 Turboのソースコードを読む(Ruby Weeklyより)
つっつきボイス:「Turboのソースコードを読みながら、リンクをクリックしてから動くまでの流れを追っていく記事です」
「ところで最近のReactを触っていると、ブラウザで動きを追える統合ツールがかなりよくできていると感じるんですが、Turboはまだデバッグツールが少ないですね」「Turboにも優秀なツール欲しいですね」「うんとリッチなWeb UIを構築するなら最初からReactでやる方がいいかな」
// 同記事より
export class LinkClickObserver {
started = false
constructor(delegate, eventTarget) {
this.delegate = delegate // set to 'session'
this.eventTarget = eventTarget // set to 'window'
}
start() {
if (!this.started) {
this.eventTarget.addEventListener("click", this.clickCaptured, true)
this.started = true
}
}
}
後編は以上です。
バックナンバー(2023年度第3四半期)
- 20230914後編 Turbo 8のTypeScriptがJavaScriptに置き換わるほか
- 20230913前編 Active Recordのenumにエラーをraiseしないvalidateオプションが追加ほか
- 20230908後編 IRB 1.8.0でデバッグ機能強化、Ruby Prize 2023開催決定ほか
- 20230906前編 システムテストでPlaywrightをサポート、to_paramのデリミタを変更可能にほか
- 20230829前編 Active Storageのミラーアップロードが非同期に、Rackアプリを手作りほか
- 20230824後編 週刊Railsウォッチ: ArelでCAST関数サポート、webdrivers依存を解消、YJIT高速化ほか
- 20230823前編 Rails 7.0.7に含まれているRails 7.0.6のバグ修正ほか
- 20230809 Rails 7.0.5のcreate_association挙動変更取り消し、YJITの性能を最大限引き出す方法ほか
- 20230803後編 Railsフラグメントキャッシュ経由の情報漏洩に注意ほか
- 20230802前編 Active Storageバリアントの事前変換、Linkヘッダープリロードのオプトアウトほか
- 20230727後編 Rubyにdefp導入の提案、IRB 1.7.3リリースほか
- 20230725前編 config.autoload_libとconfig.autoload_lib_onceが追加ほか
- 20230721後編 Kaigi on Rails 2023プロポーザル募集、rubocop-magic_numbersほか
- 20230719前編 複合主キー関連の実装進む、Action TextでHTML5サニタイザほか
- 20230705後編 AWS LambdaでRailsをRackで動かすLambyほか
- 20230704前編 productionのforce_ssl=trueがデフォルトで有効に、rakeタスクをthorで書くほか
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。
週刊Railsウォッチについて
TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)