あまり知られてないRuby/Railsの便利メソッド5つ(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

あまり知られてないRuby/Railsの便利メソッド5つ(翻訳)

私がRuby on Railsで開発するようになってかれこれ数年が経過しましたが、Ruby世界で何か新しい発見があるたびに感動があります。それこそがRubyであり、Rubyは開発者を幸せにするのが目的です(他にもいろいろ法則はありますが、とりわけ)。Rubyを使っていると、毎年何か新しいものを見つけるたびにそのことを感じます。

本記事では最近私が発見したものをいろいろご紹介いたします。これらはめったに使われていませんし、使わなければいけないものでもありません。ほとんどは「シンタックスシュガー」ですが、いずれにしろコードがとても明確になります。一部は最近のRubyやRailsの新機能です。

1. Hash#dig

Rails開発を7年続けていますが、つい最近初めてこれを見かけたときに当然「これは何?」と思いました。私がRubyで開発を始めた頃は1.8だったのですが、この機能は2.3で導入されました。

次のようなコードを何回書いたか覚えていますか。

... if params[:user] && params[:user][:address] && params[:user][:address][:somewhere_deep]

digはsafe navigation演算子(ぼっち演算子)&.の一種ですが、Hashオブジェクトで使えます。これを使えば上のコードは次のように書き直せます。

... if params.dig(:user, :address, :somewhere_deep)

2. Object#presence_in

これは、Query Objects in Ruby on Railsというお気に入りの記事を書いたときに見つけました。存在チェックの結果(論理値)が欲しいのではなく、チェックされたオブジェクトそのものが欲しい場合に、条件(多くは三項演算子)を1つのメソッドで書けます。次のコードをご覧ください。

sort_options = [:by_date, :by_title, :by_author]
...

sort = sort_options.include?(params[:sort])
  ? params[:sort]
  : :by_date

# もうひとつの方法
sort = (sort_options.include?(params[:sort]) && params[:sort]) || :by_date

上のコードを下のように書き直せまず。ずっとよくなりましたよね?

params[:sort].presence_in(sort_options) || :by_date

3. Module#alias_attribute

この便利さに気づいたのは、ある案件でレガシーなデータベースを扱っているときでした。そのデータベースのあるテーブルでは、SERNUM_0ITMDES1_0といった気持ち悪いカラム名が大量に使われていました。このテーブルをActiveRecordモデルにマップするときに、WeirdTable.where(SERNUM_0: '123')のようなクエリやスコープを書く代わりに、#alias_attributeを使うことにしました。このメソッドのよさは、述語メソッドやゲッターやセッターを生成するだけではなく、クエリで次のように使える点です。

alias_attribute :name, :ITMDES1_0
...
scope :by_name, -> (name) { where(name: name) }

4. Object#presence

このメソッドは他のものよりは知られています。ApiDockにわかりやすい説明があります。object.presenceは次と同等です。

object.present? ? object : nil

5. Module#delegate

理由はわかりませんが、このメソッドを使っている開発者をめったに見かけません。このメソッドの主な目的は、結合を弱めてデメテルの法則に沿うようにすることです。デメテルの法則についての良記事はいろいろありますが、その中でもAvdi Grimm氏の「デメテルは単なるよいアイデアではない: 法則である」が思い出されます。Rails Best Practicesの記事でも、デメテルの法則を適用するときに#delegateを使っているものがありますのでご覧ください。以下のスニペットでもおわかりいただけます。

class Profile < ApplicationRecord
  belongs_to :user

  delegate :email, to: :user
end

...
profile.email # profile.user.emailと同等

本記事でご紹介したヒントがお役に立てば幸いです。楽しくコーディングしましょう!

本記事を気に入っていただいた方は、ぜひ元記事の[✋]をクリックして応援してください。

関連記事

Railsの`Object#try`がダメな理由と効果的な代替手段(翻訳)

Rails: dry-rbでForm Objectを作る(翻訳)

3年以上かけて培ったRails開発のコツ集大成(翻訳)

Ruby on RailsによるWEBシステム開発、Android/iPhoneアプリ開発、電子書籍配信のことならお任せください この記事を書いた人と働こう! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833

コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。
これまでにRuby on Rails チュートリアル第2版の半分ほど、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れてそれぞれ一部を翻訳。
かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。
実は最近Go言語が好き。
仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

BPSアドベントカレンダー

週刊Railsウォッチ

インフラ

BigBinary記事より

ActiveSupport探訪シリーズ