Rails: コードをシンプルにする2種類の委譲(翻訳)

概要

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

日本語タイトルは内容に即したものにしました。

Rails: コードをシンプルにする2種類の委譲(翻訳)

オブジェクト指向プログラミングは、オブジェクト間のメッセージ受け渡しと考えることができます。

関連オブジェクトでは多くの場合、元のオブジェクトのメソッドであるかのように関連オブジェクトのpublicメソッドとしてアクセスできます。

これを実現する主な方法は次の2つです。

変更前

関連オブジェクトを直接呼び出す新しいメソッドを書く。

# 素のRuby
class Workspace
  attr_reader :user

  def initialize(user)
    @user = user
  end

  def user_email
    @user.email
  end
end

# Railsの場合
class Workspace < ApplicationRecord
  belongs_to :user

  def user_email
    user.email
  end
end

変更後

Forwardableの機能かdelegateメソッドを用いる。

# 素のRuby
class Workspace
  extend Forwardable

  attr_reader :user

  def initialize(user)
    @user = user
  end

  def_delegator :@user, :email, :user_email
end

# Railsの場合
class Workspace < ApplicationRecord
  belongs_to :user

  delegate :email, to: :user, allow_nil: true, prefix: true
  # allow_nil: trueにするとuserがnilの場合にエラーにならない
  # prefix: trueにするとメソッド名がuser_emailになる
end

そうすべき理由

RubyやRailsでメッセージを「パススルー」する場合、いずれかのスタイルで新しいメソッドを作成するのが望ましい方法です。これによりコードで達成しようとしていることが明確に表現できます。「単に関連オブジェクトのメソッドを呼び出す」ことと「新しい機能を実際に実装する」ことの違いを見た目ではっきりと区別できるようになり、便利です。

Railsの場合のコードでは、構文が洗練され、柔軟性も機能も向上するのが普通です。私が特に気に入っているのは、prefixオプションとallow_nilオプションです。Railsをお使いの方は、Railsがdelegation向けに提供している拡張機能をこの方法で利用できます。

そうしない理由があるとすれば

これらの機能を使ってworkspace.user.emailworkspace.user_emailに改善されるぐらいでは大したメリットは感じられません。しかしメソッド名をworkspace.owner_emailなどに変更する場合は、意図が明確になるというメリットもあるでしょう。

RubyのDelegatorライブラリ(ドキュメント)など、委譲の手法は他にもありますが、しかしこれらはいくつかのメソッドを渡すよりも、機能ごとクラス全体をラップする場合に使う方が便利です。

関連記事

Rails: ActiveRecordのスコープで`present?`を使うとパフォーマンスが落ちることがある(翻訳)

Rails: pluckでメモリを大幅に節約する(翻訳)

デザインも頼めるシステム開発会社をお探しならBPS株式会社までどうぞ 開発エンジニア積極採用中です! 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ウォッチ

インフラ

ActiveSupport探訪シリーズ