Posted at

Railsのモデルのクラスメソッド内でeachを使うときのメソッドの定義の仕方

More than 3 years have passed since last update.

以下のdestroy_all_safelyメソッドのように、where条件で返されるレコードに作用するクラスメソッドを定義することを考える.

destroy_all_safelyメソッドではeachメソッドを使って各インスタンスに処理を行うメソッドとする.

class User < ActiveRecord::Base

class << self
def call_singleton_method
User.where(id: [1, 2, 3]).destroy_all_safely
end
end
end

以下のようにクラスメソッドにするとeachがundefined method for と怒られる.

class User < ActiveRecord::Base

class << self
def destroy_all_sefely
each do |user| # => undefined method
# some processes to be safe
end
end
end
end

いくつかの実装方法があるがActiveRecord_Relationクラスをオープンしてメソッドを定義すると上手くいく.

これはUser.where(id: [1, 2, 3])で評価される結果が、User::ActiveRecord_Relationクラスのインスタンスになっているからである.

User.where(id: [1, 2, 3]).class # => User::ActiveRecord_Relation

class User < ActiveRecord::Base
class ActiveRecord_Relation
def destroy_all_safely
each do |user|
# it works
end
end
end
end


別解

オープンクラスが仰々しいという場合は以下のようにクラスメソッド内でallを呼ぶことでもできる

class User < ActiveRecord::Base

class << self
def destroy_all_safely
all.each do |user|
# it works
end
end
end
end