更新日:
【Rails】 present?メソッドの使い方やリファクタリング方法とは
present?メソッドとは、present?メソッドを使用したオブジェクトが存在すればtrueを返し、存在しなければfalseを返すメソッドです。
1
オブジェクト.present?
1
2
3
4
5
site_name = 'pikawaka'
=> ""
site_name.present?
=> true
この記事では、present?メソッドの基本的な使い方、present?メソッドを使ったリファクタリング方法、他の真偽値判定メソッドについて解説します。
present?メソッドの使い方
present?メソッドはActiveSupportで定義されているメソッドです。
1
2
3
def present?
!blank?
end
present?メソッドは上記の様に定義されております。
!blank?
ということは、blank?メソッドの返り値の反対がpresent?メソッドの返り値になります。blank?メソッドは真偽値(trueかfalse)を返すメソッドなので、blank?メソッドがtrueならpresent?メソッドはfalse、blank?メソッドがfalseならpresent?メソッドはtrueを返すということですね。
blank?メソッドの挙動の詳細については後述するので、ここではpresent?メソッドの返り値は必ずblank?メソッドの反対になるんだな〜と理解しておきましょう。
present?メソッドがtrueになる場合・falseになる場合のオブジェクト
present?メソッドがblank?メソッドの返り値の反対の結果になるということは分かりましたが、具体的にどんなオブジェクトがtrue・falseを返すか見ていきましょう
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
str = ''
str.present?
=> false
str = ' '
str.present?
=> false
arr = []
arr.present?
=> false
key_value = {}
key_value.present?
=> false
false.present?
=> false
nil.present?
=> false
present?メソッドがfalseの場合を見てみると、空文字、空白文字、配列の器、hashの器、false、nilの場合はpresent?メソッドの返り値はfalseになってます。つまりstringや配列、ハッシュなど型の器はあっても中身がない場合はfalseになっていることがわかります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
str = 'str'
str.present?
=> true
arr = ['arr']
arr.present?
=> true
key_value = {key: 'value'}
key_value.present?
=> true
true.present?
=> true
そして、それぞれの型で中身がある場合はtrueを返します。つまり、present?メソッドがtrueであればレシーバーのオブジェクトがどんな型でも何かしら値が入っているのだなと考えてください。逆にpresent?メソッドがfalseならばレシーバーのオブジェクトがarrayなど器はあっても中身はないと考えると分かりやすいので、まずはざっくりそのように覚えましょう。
present?メソッドを三項演算子で書いてみよう
present?メソッドの返り値は真偽値(true or false)を返すので、三項演算子を使って処理をかけます。
三項演算子とは、下記のように「条件式 ? 条件が正しい場合 : 条件が正しくない場合」と一行でif elseの様な条件分岐を簡潔に書く方法です。
1
2
3
4
5
6
7
site_name = 'pikawaka'
site_name == 'pikawaka' ? 'このサイトはpikawakaです。' : 'このサイトはpikawakaではありません'
=> "このサイトはpikawakaです。"
site_name = 'hoge'
site_name == 'pikawaka' ? 'このサイトはpikawakaです。' : 'このサイトはpikawakaではありません'
=> "このサイトはpikawakaではありません"
詳しく知りたい方は「三項演算子の使い方」を参照してください。
この三項演算子を応用するとpresent?メソッドが真偽値を返すことから、「条件式 ? もし値があった場合:もし値がなかった場合」という様に一行で簡潔に書くことができます。例題を見てみましょう。
1
2
3
4
5
6
7
arr = ['arr']
arr.present? ? '配列の中に値が入っています' : '配列の中身は空です'
=> "配列の中に値が入っています"
arr = []
arr.present? ? '配列の中に値が入っています' : '配列の中身は空です'
=> "配列の中身は空です"
このようにpresent?メソッドと三項演算子を一緒に使うとif文で5行くらい書かなければいけないコードが
1
2
3
4
5
6
7
8
arr = ['arr']
if arr.present?
'配列の中に値が入っています'
else
'配列の中身は空です'
end
=> "配列の中に値が入っています"
一行で簡潔に書ける様になるので、if elseの条件分岐を使ってる人は三項演算子で簡潔に書けないか考えてみましょう。
1
2
3
arr = ['arr']
arr.present? ? '配列の中に値が入っています' : '配列の中身は空です'
=> "配列の中に値が入っています"
present?メソッドをpresenceメソッドでリファクタリングしてみよう
present?メソッドと三項演算子を使って値がある場合・値がない場合を一行で書ける簡潔な方法を紹介しましたが、presenceメソッドを使うとより簡潔に書くことができます。
presenceメソッドとは、オブジェクト.present?がtrueならばオブジェクトを返し、falseならばnilを返すメソッドです。
presenceメソッドがどの様なメソッドか具体例を見てみましょう。
1
2
3
4
5
6
7
arr = ['arr']
arr.presence
=> ["arr"]
arr = []
arr.presence
=> nil
上記の例で行くと['arr'].present?はtrueになるので['arr']を返し、[].present?はfalseなのでnilを返しました。このnilを返す特徴と || を利用するとオブジェクトが存在するならばオブジェクトを返し、存在しないならば || 以降の処理を返すということが簡単に書ける様になります。
1
2
3
4
5
6
7
arr = ['arr']
arr.presence || '配列の中身は空です'
=> ['arr']
arr = []
arr.presence || '配列の中身は空です'
=> "配列の中身は空です"
|| 演算子の使い方について知らない方は 「論理演算子(!, &&, ||, not, and, or)をまるごと学ぼう!」を参照してください。
presence || ~~を使うとこのように短く書けます。presenceメソッドと三項演算子を見比べてみましょう。
1
2
3
4
# 下の2つのコードは同じ意味になります。
['arr'].present? ? ['arr'] : '配列の中身は空です'
['arr'].presence || '配列の中身は空です'
=> ['arr']
presenceメソッドを使えば、このように三項演算子よりも処理を簡潔に書くことができます。
上の例はコード量が少ないのでどれだけリファクタリングができたか分かりにくいですが、数が多くなるとpresenceメソッドでより簡潔にかけていることを実感できます。下記の例を見てみましょう。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def get_blood_type(a_type, b_type, ab_type, o_type)
if a_type.present?
'血液型はA型です。'
elsif b_type.present?
'血液型はB型です。'
elsif ab_type.present?
'血液型はAB型です。'
elsif o_type.present?
'血液型はO型です。'
end
end
a_type = ''
b_type = ''
ab_type = ''
o_type = '血液型はO型です。'
blood_type = get_blood_type(a_type, b_type, ab_type, o_type)
p blood_type
=> "血液型はO型です。"
このコードを下記にリファクタリングできます。
1
2
3
4
5
6
7
8
9
10
11
12
def get_blood_type(a_type, b_type, ab_type, o_type)
a_type.presence || b_type.presence || ab_type.presence || o_type.presence
end
a_type = ''
b_type = ''
ab_type = ''
o_type = '血液型はO型です。'
blood_type = get_blood_type(a_type, b_type, ab_type, o_type)
p blood_type
=> "血液型はO型です。"
このようにpresenceメソッドで冗長なif文をリファクタリングできます。
presenceメソッドは大変便利なメソッドです。presenceメソッドのより詳細な使い方を知りたい方は「presenceメソッドの使い方」を参照してください。
Ruby on Railsを体系的に学びたい!という方は、こちらの基礎から複数人での開発体制など学べる参考書を手元に置いておくと良いでしょう。
present?メソッド以外の真偽判定メソッド
ここまでpresent?メソッドの使い方やリファクタリングの方法について説明してきました。この章ではpresent?メソッドの様に存在チェック系等の真偽値を返すメソッドについて説明していきます。
blank?メソッド
記事の冒頭で説明したblank?メソッドです。present?メソッドはblank?メソッドで実行した真偽値の反対の真偽値が出ると説明しましたが、blank?メソッドが実際にどの様なオブジェクトに対してtrueやfalseを実行するか見ていきましょう。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
str = ''
str.blank?
=> true
str = ' '
str.blank?
=> true
arr = []
arr.blank?
=> true
key_value = {}
key_value.blank?
=> true
false.blank?
=> true
nil.blank?
=> true
present?メソッドが!blank?で定義されていると説明した通り、present?メソッドがfalseになるパターンはblank?メソッドでは全てtrueになります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
str = 'str'
str.blank?
=> false
arr = ['arr']
arr.blank?
=> false
key_value = {key: 'value'}
key_value.blank?
=> false
true.blank?
=> false
逆にpresent?メソッドがtrueになる場合はblank?メソッドは全てfalseになります。
blank?メソッドとpresent?メソッドは常に真偽値の結果が反対になると覚えておきましょう。
nil?メソッド
nil?メソッドの動作は簡単です。オブジェクトがnilであればtrueを返し、nilでなければfalseを返します。
空文字や配列の器、ハッシュの器だけでも全てfalseを返します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
nil.nil?
=> true
''.nil?
=> false
' '.nil?
=> false
[].nil?
=> false
{}.nil?
=> false
false.nil?
=> false
nil?はnilに対してはtrueを返し、それ以外に関しては全てfalseを返すと覚えておきましょう。
empty?メソッド
empty?メソッドについて説明します。empty?メソッドはString、Array、Hash等に定義されているメソッドで、nilや真偽値オブジェクトに対して実行するとエラーを出力します。具体的にどのオブジェクトではtrueになり、どのオブジェクトではfalseになるか見ていきましょう。
1
2
3
4
5
"".empty?
=> true
" ".empty?
=> false
空文字ならばtrueを返し、空白文字でも入っていたらfalseを返します。
1
2
3
4
5
[].empty?
=> true
[' '].empty?
=> false
配列も要素が0ならばtrueを返しますが、空白文字でも要素が存在するならばfalseを返します。
1
2
3
4
5
{}.empty?
=> true
{hoge: 'hogehoge'}.empty?
=> false
hashも配列と同じで、中身がない器だけの場合はtrueを返し、key valueのペアが存在すればfalseを返します。
1
2
3
4
5
6
7
8
9
10
11
nil.empty?
NoMethodError: undefined method `empty?' for nil:NilClass
true.empty?
NoMethodError: undefined method `empty?' for true:TrueClass
false.empty?
NoMethodError: undefined method `empty?' for false:FalseClass
10.empty?
NoMethodError: undefined method `empty?' for 10:Integer
このようにNilClass、Integerクラス、TrueClass、FalseClassには定義されておらずエラーが出てしまうので注意が必要です。
exists?メソッド
exists?メソッドは指定したレコードがDBにあるかどうかを真偽値で返すメソッドです。
1
2
3
4
5
User.exists?(age: 20)
=> true
User.exists?(age: 19)
=> false
上記の例で言うと、User.exists?(age: 20)でtrueが返ってきているので、usersテーブルに20歳のユーザーがいることを表しています。そしてUser.exists?(age: 19)がfalseなので、usersテーブルに19歳のユーザーがいないことを表しています。
このように指定したレコードが存在するかしないかを真偽値で返してくれるので、レコードのデータを使わずにデータの存在チェックだけをしたい場合にはかなり便利なメソッドになります。
データの存在チェックで真偽値を返すメソッドを表でおさらいしよう
present?メソッド以外にもオブジェクトの存在チェックをするメソッドを説明しました。それぞれのメソッドで似ているが微妙に挙動が違うメソッドなどもあったので、最後にそれぞれのメソッドが返す真偽値に対して簡単に表で見直しましょう。
present? | blank? | nil? | empty? | |
---|---|---|---|---|
''(空文字) | false | true | false | true |
' '(空白文字) | false | true | false | false |
[](空配列) | false | true | false | true |
[' '](配列要素あり) | true | false | false | false |
{}(空ハッシュ) | false | true | false | true |
{hoge: 'hogehoge'}(ハッシュ要素あり) | true | false | false | false |
1000 | true | false | false | NoMethodError |
nil | false | true | true | NoMethodError |
true | true | false | false | NoMethodError |
false | false | true | false | NoMethodError |
存在チェックのメソッドでどのメソッドを使うか悩んだときはこの表を見て適切なメソッドを使う様にしましょう!
この記事のまとめ
- present?メソッドは中身があればtrueを返し、器だけならfalseを返す
- if文の条件分岐や三項演算子でpresent?メソッドを使っていればpresence || ~~の形でリファクタリングできる
- 存在チェックで似ているメソッドはたくさんあるので、適切な存在チェックのメソッドを使う様にしよう