noneメソッドを通して学んだこと

こんにちは!oda@エンジニア1年目です!

先日、Railsで空のモデルオブジェクトを取得したいということがありました。

今日はその時に学んだことついて、書いてみようと思います。

事前準備

今回はBookモデルを例に進めていきます。

Bookモデルには、次のデータをあらかじめ準備しています。

title category stock
小説1 novel 3
小説2 novel 2
マンガ1 comic 0
マンガ2 comic 1
料理1 cooking 2
料理2 cooking 4

そして、Bookモデルのレコードを全件取得しておきます。

books = Book.all

空のモデルオブジェクトを取得してみる

そもそも、空のモデルオブジェクトはnoneメソッドを使わなくても、whereメソッドを使って条件を満たすレコードがなかった時などにも返ってきます。

books.where(category: 'science')
# => []

日頃、この返り値を見て「条件を満たすレコードがない時は空の配列が返ってきてるなー」と何となく思っていましたが、ここが間違いでした。

私はnoneメソッドを知る前、空のモデルオブジェクトを取得したくて以下のようなコードを書きました。

books = []
# => []

しかし、同じ返り値のように見えるこの2つには大きな違いがありました。

私がこの間違いに気がついたのは取得したbooksに、さらにwhereメソッドを使った時です。

違いがよくわるかようにそれぞれのbooksのクラスも確認してみます。

books = books.where(category: 'science')
# => []

books.where('stock > ?', 0)
# => []

books.class
# => Book::ActiveRecord_Relation
books = []
# => []

books.where('stock > ?', 0)
# => undefined method `where' for []:Array (NoMethodError)

books.class
# => Array

RailsのActiveRecordのメソッドであるwhereメソッドは、Arrayクラスには使えません。

そのため、空の配列をbooksに入れると、上記のとおりNoMethodErrorが発生してしまいました。

そして、空のモデルオブジェクトを取得するためにはどうしたらいいのだろうかと調べてnoneメソッドの存在を知りました。

先ほどと同じようにnoneメソッドを試すと、以下のように空のモデルオブジェクトを取得できていることが確認できます。

books = books.none
# => []

books.where('stock > ?', 0)
# => []

books.class
# => Book::ActiveRecord_Relation

さいごに

今回の件では、noneメソッドを新たに知ることができました。

ただ、最大の収穫は新たなメソッドを知ったことではなく、返り値のクラスを常に意識しなければならないということに気がついたことです。

こういった気づきを大事にしながら、今後もレベルアップしていきたいと思います!