私はActiveRecordの新しいクエリインターフェイスを初めて使用するので、まだ理解していません。
私は、誰かがActiveRecordモデルでscope
を使用することと、クラスメソッド(つまりself.some_method
)を使用することの違いを説明できることを望んでいました
私が収集できるものから、スコープは常に関係を返すことが期待されていますが、クラスメソッドは必ずしもそうである必要はありません。これは本当ですか?
たとえば、次のようなことをすると理にかなっていると思いました。
class Person
scope :grouped_counts, group(:name).count
end
しかし、これは機能しません。私はこのエラーを受け取ります:
ArgumentError: Unknown key(s): communicating, failed, matched, unmatched
from /Users/bradrobertson/.rvm/gems/Ruby-1.9.2-p180@influitive/gems/activesupport-3.0.5/lib/active_support/core_ext/hash/keys.rb:43:in `assert_valid_keys'
from /Users/bradrobertson/.rvm/gems/Ruby-1.9.2-p180@influitive/gems/activerecord-3.0.5/lib/active_record/relation/spawn_methods.rb:110:in `apply_Finder_options'
from /Users/bradrobertson/.rvm/gems/Ruby-1.9.2-p180@influitive/gems/activerecord-3.0.5/lib/active_record/named_scope.rb:110:in `block in scope'
from (irb):48
from /Users/bradrobertson/.rvm/gems/Ruby-1.9.2-p180@influitive/gems/railties-3.0.5/lib/Rails/commands/console.rb:44:in `start'
from /Users/bradrobertson/.rvm/gems/Ruby-1.9.2-p180@influitive/gems/railties-3.0.5/lib/Rails/commands/console.rb:8:in `start'
from /Users/bradrobertson/.rvm/gems/Ruby-1.9.2-p180@influitive/gems/railties-3.0.5/lib/Rails/commands.rb:23:in `<top (required)>'
from script/Rails:6:in `require'
from script/Rails:6:in `<main>'
r
ただし、クラスメソッドとして機能します
def self.grouped_counts
group(:name).count
end
スコープをいつ使用し、いつクラスメソッドを使用するかについての人々の考えを知りたいです。スコープは常にリレーションを返す必要があると思いますが、クラスメソッドは何でも返すことができますか?
Rails 2.x、named_scopesはクエリを実行しなかったため(連鎖できるように)、クラスメソッドは一般にクエリを実行したため(連鎖できないため)、さらに多くの違いがありました。クエリを手動でscoped(...)
呼び出しでラップした場合を除きます。
Rails 3では、実際の結果が必要になるまですべてがActiveRecord::Relation
を返すため、スコープをクラスメソッドに対してチェーンでき、その逆も可能です(クラスメソッドがActiveRecord::Relation
オブジェクトであり、他のオブジェクトタイプ(カウントなど)ではありません)。
通常、単純な1行のscope
エントリを使用して、結果セットをフィルタリングします。ただし、詳細なロジック、ラムダ、複数行などが必要になる可能性のある「スコープ」で複雑なことを行う場合は、クラスメソッドを使用することをお勧めします。そして、あなたがキャッチしたように、カウントなどを返す必要がある場合は、クラスメソッドを使用します。
Dylan が彼の答えで言及したように、スコープとクラスメソッドの1つの違いは、クラスが読み込まれるときにスコープが評価されることです。これにより、予期しない結果が生じる可能性があります。
例えば、
class Post < ActiveRecord::Base
scope :published_earlier, where('published_at < ?', Date.today)
end
エラーが発生しやすい。正しい方法はラムダを使用することです
class Post < ActiveRecord::Base
scope :published_earlier, -> { where('published_at < ?', Date.today) }
end
Lambdaブロックは遅延評価されます。したがって、Date.todayは、クラスが評価されるときではなく、スコープを呼び出すときに実行されます。
クラスメソッドを使用する場合は、ラムダを使用する必要はありません。
class Post < ActiveRecord::Base
def self.published_earlier
where('published_at < ?', Date.today)
end
end
クラスメソッドの場合、コードはメソッド呼び出し時に実行されるためです。