あまり知られてない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
- Rails API:
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
- Rails API:
Module#alias_attribute
この便利さに気づいたのは、ある案件でレガシーなデータベースを扱っているときでした。そのデータベースのあるテーブルでは、SERNUM_0
やITMDES1_0
といった気持ち悪いカラム名が大量に使われていました。このテーブルをActiveRecordモデルにマップするときに、WeirdTable.where(SERNUM_0: '123')
のようなクエリやスコープを書く代わりに、#alias_attribute
を使うことにしました。このメソッドのよさは、述語メソッドやゲッターやセッターを生成するだけではなく、クエリで次のように使える点です。
alias_attribute :name, :ITMDES1_0
...
scope :by_name, -> (name) { where(name: name) }
🔗 4. Object#presence
- Rails API:
Object#presence
このメソッドは他のものよりは知られています。ApiDockにわかりやすい説明があります。object.presence
は次と同等です。
object.present? ? object : nil
🔗 5. Module#delegate
- Rails API:
Module#delegate
理由はわかりませんが、このメソッドを使っている開発者をめったに見かけません。このメソッドの主な目的は、癒着を弱めてデメテルの法則に沿うようにすることです。デメテルの法則についての良記事はいろいろありますが、その中でもAvdi Grimm氏の「デメテルは単なるよいアイデアではない: 法則である」が思い出されます。Rails Best Practicesの記事でも、デメテルの法則を適用するときに#delegate
を使っているものがありますのでご覧ください。以下のスニペットでもおわかりいただけます。
class Profile < ApplicationRecord
belongs_to :user
delegate :email, to: :user
end
...
profile.email # profile.user.emailと同等
本記事でご紹介したヒントがお役に立てば幸いです。楽しくコーディングしましょう!
本記事を気に入っていただいた方は、ぜひ元記事の[✋]をクリックして応援してください。
概要
原著者の許諾を得て翻訳・公開いたします。