ホーム DoRuby tryの使い方と注意点
tryの使い方と注意点
 

tryの使い方と注意点

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Railsのtryを使用するにあたってのアドバイスを頂いたので、今回は、tryについてまとめてみました。

tryとは?

 簡単に説明すると、レシーバがnilでもNoMethodErrorが発生せずに、nilを返してくれるメソッドです。このメソッドは、railsのactivesupportというgemをインストールすると使用することができます(ほとんどの場合、Railsの環境構築をすると入っています)。tryの細かい動きについては、自分の環境のactivesupport4.1.4のコードが分かりやすかったので、こちらのコードを使用して説明していきます。※バージョンによっては、処理内容が異なる可能性があります。(githubのactivesupportのコード:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/object/try.rb)

activesupport-4.1.4/lib/active_support/core_ext/object/try.rb

class Object
  def try(*a, &b)
    if a.empty? && block_given?
      yield self
    else
      public_send(*a, &b) if respond_to?(a.first)
    end
  end

  def try!(*a, &b)
    if a.empty? && block_given?
      yield self
    else
      public_send(*a, &b)
    end
  end
end

class NilClass
  def try(*args)
    nil
  end

  def try!(*args)
    nil
  end
end

 見て貰えれば分かりますが、レシーバがnilの場合は、引数に関わらず必ずnilが返るようになっています。次に、レシーバがオブジェクトの場合のtryとtry!の違いに注目してみます。tryは、respond_to?でメソッド名が正しくない場合に、メソッドを実行しないので、エラーが発生しませんが、try!は、respond_to?が無い為、メソッド名が正しくない場合は、NoMethodErrorが発生してしまいます。

 下記のクラスとデータを使用してtryを使用した簡単な例を挙げます。(Person.job_idは、Job.idの外部キー)

class Job < ActiveRecord::Base
  has_many: persons
end

class Person < ActiveRecord::Base
  belongs_to: job
end
enter image description here
# Aさんの仕事を取得
person_a = Person.find_by(name: 'A')
person_a.job.job_name
=> engineer

# Bさんの仕事を取得
person_b = Person.find_by(name: 'B')
person_b.job.job_name
=> NoMethodError # Bさんは仕事(job_id)を持っていないので、仕事名を取得すると、NoMethodErrorが発生します。

# tryを使用すると、NoMethodErrorを回避することができます。
person_b.job.try(:job_name)
=> nil

tryをチェインするときの注意点

 tryをチェインするときは、原則tryを使用します。レシーバがnilでもエラーが出ないto_spresent?メソッドなどの場合のみtryを使用しなくても良いです。tryは、レシーバがnilになる可能性がある場合に使用する為、tryの後にnilで動かないメソッドを記述するとエラーの原因となります。

person_c = Person.find_by(name: 'C')

# 悪い例
person_c.try(:job).job_name
person_c.try(:job).try(:job_name).swapcase

# 良い例
person_c.try(:job).try(:job_name)
person_c.try(:job).try(:job_name).try(:swapcase)
person_c.try(:job).present?

記事を共有

最近人気な記事