私だけが知ってるRails標準機能 1分LT会〜社内勉強会SG Techレポート
ソニックガーデンの社内勉強会「SG Tech」では、メンバーが技術の知見を持ち寄って共有し合っています。6月のテーマは「私だけが知ってるRails標準機能 1分LT会」。事前アンケートで集まった機能を眺めながら、雑談混じりに語り合う回になりました。本レポートでは当日の模様をお届けします。
22個の「自分だけが知ってるかも」
今回の企画はkzkn(かずくん)の持ち込み。
※kzknはRailsのパンくずリストを手軽に実装できるgem「gretel」のメンテナを務めているメンバー。
事前に全員へアンケートを送り「自分だけが知ってるかもしれないRailsの標準機能」を1個挙げてもらう、というシンプルなルール。集まった回答は22個。それをHTMLにまとめ、当日はみんなで一覧を眺めながら順に話していく、という形で進めました。
(ちなみにこのHTML、Googleフォームで集めた回答をスプレッドシートに集約したものをClaudeでHTML化しました)
ActiveRecordのクエリ系からビューヘルパー、バリデーション、さらにはRuby本体の機能まで実に幅広いものに。「自分だけが知ってるかも」という前提で集めているだけあって、「それ知らなかった!」「どう使ってる?」という声が上がることも多く、自然と雑談が盛り上がる場になりました。
普段は当たり前のように使っている技術も、アップデートで機能が追加されていたりニッチな機能があったりしますよね。そんな気づきから始まった回でした。
盛り上がった機能をいくつか紹介
Enumerable#pluck ―― 配列やAPIレスポンスからも値を抜き出せる
ActiveRecordのpluckはおなじみだと思いますが、実はEnumerableレベルでも同名のメソッドが使えます。ActiveSupportがHash配列などに対してもpluckを生やしてくれているので、SQLを発行せずに「特定のキーの値だけをまとめて取り出す」ことができます。
users = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" },
]
users.pluck(:name) # => ["Alice", "Bob"]
users.pluck(:id, :name) # => [[1, "Alice"], [2, "Bob"]]
外部APIのレスポンス(JSON)を扱うときなどに重宝します。「私もよく使ってます」「外部APIから取ってきたデータの一部だけ欲しいときにかなり便利」という声が複数のメンバーから上がり、すでに実戦投入しているメンバーが何人もいたのが印象的でした。
normalizes ―― 検索時にも自動でノーマライズされる
保存前のデータクレンジングに使えるnormalizes。メールアドレスを小文字に揃える、電話番号の表記ゆれを整える、といった用途で便利です。
class User < ApplicationRecord normalizes :email, with: ->(email) { email.strip.downcase } end
盛り上がったのは「保存時だけでなく、whereでの検索時にも同じように正規化される」という点。
User.where(email: " PERSON@Example.com ") # => 正規化されて "person@example.com" で検索される
「大文字で入力されても小文字で検索できる。ユーザー目線で考えるとすごく便利」という説明に、知らなかったメンバーから「そこまでやってくれるのか」という反応がありました。
sole / find_sole_by ―― 「ちょうど1件」を保証する
findやfind_byと違い、結果がちょうど1件でなければ例外を投げるのがsole。0件ならRecordNotFound、2件以上ならSoleRecordExceededを発生させます。
Product.where(code: "ABC").sole # 1件ならそのレコード、それ以外は例外 Product.find_sole_by(code: "ABC") # whereとsoleをまとめた書き方
「メソッド名で『ここは1件のはず』という意図を伝えられるし、もしデータがおかしくなっていたら例外で気づける」という紹介でした。テストや整合性チェックのためというより、実際のビジネスロジックの中でデータ異常を早期に検知できる点が評価されていました。
ActiveRecord::DelegatedType ―― 共通の構造をきれいに扱うための仕組み
STI(単一テーブル継承)の課題を解消するために用意されたDelegatedType。「使ったことはないんですが、使ってるのを見てみたい、という気持ちで書きました」という正直な一言に、会場で笑いが起きる一幕もありました。
STIだと1つのテーブルに複数の型の知識が混在しがちですが、DelegatedTypeはテーブルを型ごとに分けたうえでポリモーフィックに束ねる、という設計パターンを標準でサポートします。たとえば「Entry(共通の入り口)が、MessageやCommentといった具体型に委譲する」といった構成です。認証情報の一元管理などに向いている、という話も出ました。
また、この会をきっかけに、参加者の伊藤(@jnchito)が「【Rails】給湯器のサンプルアプリで学ぶDelegatedType」という記事も書いていますのであわせてご覧ください。
1行パターンマッチによる型アサーション ―― Rubyの機能として
こちらはRailsではなくRuby本体の機能。Ruby 3.0で導入された1行パターンマッチ(=>)を使って、引数の型をチェックする使い方が紹介されました。
def search(query, type, score) type => 'HYBRID' | 'SEMANTIC' score => 0.0..1.0 # ここに来た時点で type と score が条件を満たしていることが保証される end
想定外の型が渡されると例外が上がる、というシンプルな使い方です。「パッと見で意図を汲み取るのは難しいかもしれないので、分かりにくくなりそうなところだけに絞って書いています。気に入った人は使ってみてください」というみんなにこの便利さを伝えたい!という紹介もありました。
若手レビューで伝えているTips集
「若手にレビューするときに伝えていること」をまとめて紹介してくれたメンバーも。
機能そのものの紹介ではなく、コードの書き方や読みやすさにまつわるノウハウ集でした。
これが特に好評でした。
短い処理を上に書く
Emptyステートや早期リターンを先に書いておくと、読む人が本質的な処理に集中しやすくなる。条件分岐のネストも浅くなります。
changeは&記法でつなぐ
RSpecでchangeのマッチャを複数並べるとき、アンパサンドでつなぐとインデントが深くならず読みやすい。
expect do # 何らかの処理 end.to( change(EventScheduleParticipation.reported, :count).to(0) & change(event_schedule_participation, :status).to('approved') )
have_enqueued_jobのブロック内で検証する
エンキューされたジョブの引数などをブロック内で検証することで、テストの意図がはっきりする。
createのブロックで関連データをまとめる
ファクトリのcreateにブロックを渡すと、関連データをまとめて作れるうえ、一時変数のスコープが外に漏れずに済む。
「言われてみれば当たり前なんですが、こうして言語化してもらうと改めて気づきがある」という反応があり、暗黙知の言語化こそ勉強会の価値のひとつだと感じる時間になりました。
技術を肴にわいわいする
「自分だけが知ってるかも」という切り口で集めたアンケートには、同じ機能を複数のメンバーが挙げたものもありました。それがまた「なんだ、みんな知ってるじゃん(笑)」という雑談につながり、場の空気をほぐすきっかけに。「それどこで使った?」「自分はこう使ってる」と、ひとつの機能から話が横に広がっていくのも楽しい時間でした。
こんなふうに技術を肴にわいわいできるところが社内勉強会の魅力でもあります。1分LTという軽い形式なら、「完璧に調べ上げて発表する」のではなく「使ったことがある」「気になっている」くらいの温度感で持ち寄れる。肩の力が抜けているぶん、雑談から思わぬ発見が生まれる。今回もまさにそんな場になりました。
ソニックガーデンのプログラマ文化に興味をお持ちの方は、ぜひ採用情報もご覧ください。
【経歴】パッケージソフトウェア開発を経て、2021年に中途入社。プログラマ経験を活かして、採用・育成・イベント企画運営などを担当している。
【ソニックガーデンで働く面白さ】考えて動いて、うまくいかなければ捨てて、また始める。採用もイベントも育成も地続きにつながっていて、その全部に関われること。