はじめに
ActiveRecord::Relationはレコードの集まりであるが、Railsでアプリケーションを開発している時に、ActiveRecord::Relationに対してのメソッドを定義したい時が幾度もある。具体的な例とその手法を見ていきたい。
本編
ActiveRecord::Base
とActiveRecord::Relation
の関係
各々のモデル、ActiveRecord::Base
、ActiveRecord::Relation
のオブジェクトに対応推している。
例えば、User
というモデルについて考えてみる。
現在、users
テーブルにはレコードが下の様に入ってたとする。
id | name | power(億単位) | |
---|---|---|---|
1 | カカロット | ninjin@saiya.com | 130 |
2 | ベジータ | yasai@saiya.com | 75 |
3 | 18号 | kuririn.love@kikai.com | 13 |
4 | セル | sell@kanzentai.com | 300 |
5 | ピッコロ | gohan.love@namekku.com | 20 |
6 | ゴハン | gohan@saiya.com | 300 |
Userのレコードを全て所得すれば、以下のように表示される。
User.all
=> #<ActiveRecord::Relation [#<User id: 1, name: "カカロット", email: "ninjin@saiya.com", power: "130">, #<User id: 2, name: "ベジータ", email: "yasai@saiya.com", power: "75億"> ... 省略]>
つまり、 ActiveBase::Relation
クラスのインスタンスを返しているのである。
all
おそらく、最も一般的なものはクラスメソッド内で、allを使う手法である。
考えてみれば、当たり前なんだけど気づかなんだ。
例:ActiveRecord::Relation内にフリーザーよりも強いやつが一人でもいたらtrueを返すメソッド
class User
def self.can_beat_freezer?
# 便宜上、Freezer.power が 0.0053 (53万) を返すことにします。
# 上記のメンバーだとヘナチョコのボコボコのペチャペチャのギッタンギッタンですね
all.pluck(:power).any? { |power| power > Freezer.power }
end
end
他にも、relation
method などありますが、all
はrelation
を間接的に呼び出しているので、all
の方がいいでしょう。
バージョンが低い場合は(3以下かな?) @relation
や scoped
などがあったようです。(よく知らない)。
クラス化
このように少しでもロジックが入ってしまうと、メソッドにしまいたいですね。
今回のように、戦闘力を比較して解決してしまう比較的単純なメソッドならばする必要はゼロなのですが、比較的複雑なメソッドをこのようにどんどんモデルにメソッドを足していくとデブモデルが出来てしまい、収拾がつかなくなります。そこで、このようなメソッドはクラスにするのがいいでしょう。
class BeatingFreeza
class << self
def possible?(collection)
new(collection).possible?
end
end
def initialize(collection)
@collection = collection
end
def possible?
collection.pluck(:power).any? { |power| power > Freezer.power } ||
collection.any? { |user| user.super_saiya? } ||
# ....... 以下戦闘力だけではなく、環境や頭の回転などを考慮するようになってくるとこのようにするのがいいでしょう。
# ドラゴンボールは戦闘力で決まってしまうので、ハンターハンターとかのときには、クラスを別途で作りましょう。
end
end
class User < ActiveRecord::Base
def self.can_beat_freeza?
BeatingFreeza.possible?(all)
end
end
ちなみに
ドドリアなどの部下(果物)やサイヤ人(野菜)、リクームとかギニュウ(クリームと牛乳)を統括するフリーザ(冷凍庫)っていうことらしい。それがスーパーな人参に負けてしまうんだから、奇跡だな。