10
1

【rails】 ActiveRecord exists? present? empty? blank? の使い分けどころ

Last updated at Posted at 2023-12-05

はじめに

初学者の頃から分かったような気がするけど、適切に使いこなせてなかった
ActiveRecordexists?, present?, empty?, blank?
使い分けについて最近やっと腑に落ちたのでメモリます。

exists

データが1件でもあるかどうかチェックするにはModel.exists?を使う。
どういうことかというと

 Pokemon.exists?
  Pokemon Exists? (98.6ms)  SELECT 1 AS one FROM `pokemon` LIMIT 1
=> true             

ポイントになるのがSELECT 1 AS というところ。
データが1行以上「あるかどうか」だけが問題となります。
ということで、データの値を取ってくる必要がないため、
カラムの情報が一切ないことがわかります。

ちなみにこれと反対の意味を持つのがempty?である

blank?

Pokemon.where(type: 'FIRE').blank?
  Pokemon Load (481.6ms)  SELECT `pokemon`.* FROM `pokemon` WHERE `pokemon`.`type` = 'FIRE'
=> true  

ポイントはSELECT pokemon.* の部分で、条件にマッチするデータを全て、カラム情報込み で取得していることがわかる。

ちなみにこれと反対の意味を持つのがpresent?である

では、 どんな時に使い分けると嬉しいか

ある特定の条件を満たすデータがデータベースに存在するかどうかを確認する場合に、exists? が適しています。(存在しないことを確認したいなら empty?

これはデータの有無だけが気になる場合で、具体的なデータの値を使用しないときです。

if pokemon.exists?(type: 'Fire')
  puts "炎タイプのポケモンが登録されていません。"
else
  puts "炎タイプのポケモンは登録されています。"
end

一方で、present? / blank? は特定の条件を満たすデータがデータベースに存在するかだけでなく、それらのデータの値も利用する場合 に使いたい。

fire_pokemon = Pokemon.where(type: 'FIRE')

return if fire_pokemon.blank? # この時点で必要なデータも取得できている

puts "Fire タイプのポケモンが存在します。"
# blank?で取得したデータを利用するので、発行されるSQLは1件のみ
puts "それらのポケモン: #{fire_pokemon.pluck(:name).join(', ')}"

仮に、データの値も利用する場合に empty? を使ってしまうと、後でデータを使用する時に、改めてデータを引いてしまうので、DBサーバーにアクセスする回数が2回になってしまう。

fire_pokemon = Pokemon.where(type: 'FIRE')

return if fire_pokemon.empty? #  データが存在するどうかを確認するためにDBにアクセス

# 利用するデータを引くためにDBに再アクセスする必要がある
puts "それらのポケモン: #{fire_pokemon.pluck(:name).join(', ')}" 

一概にデータの確認の際にはempty?と決めに行くのではなく、
処理全体の内容によってempty? / blank?, exists? / present?
使い分けるようにしたい。

最後に

ここまで見てくださりありがとうございます。m(_ _)m
この手の記事は山ほどありますが、自身の勉強視点でまとめてみた感じです。

誰かの役に立てば嬉しいです。

10
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
1