53

私は ActiveRecord の新しいクエリ インターフェイスに慣れていないので、まだいろいろと考えています。

scopeActiveRecord モデルで a を使用することと、単にクラス メソッドを使用することの違いを誰かが説明してくれることを期待していました (つまり、 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

いつスコープを使用し、いつクラスメソッドを使用するかについて、人々の考えを知りたいです。スコープは常に関係を返さなければならないが、クラスメソッドは必要なものを返すことができると仮定するのは正しいですか?

4

2 に答える 2

86

Rails 2.x ではより多くの違いがありました。named_scopes はクエリを実行しなかったため (チェーンできるため)、クラス メソッドは一般的にクエリを実行しました (チェーンできないため)。scoped(...)通話中。

Rails 3 ではActiveRecord::Relation、実際の結果が必要になるまではすべてが返されるため、クラス メソッドに対してスコープをチェーンしたり、その逆をチェーンしたりすることができます (クラス メソッドがActiveRecord::Relation他のオブジェクト タイプ (カウントなど) ではなくオブジェクトを返す限り)。

通常、scope単純なワンライナーのエントリを使用して、結果セットをフィルタリングします。ただし、詳細なロジック、ラムダ、複数の行などを必要とする可能性のある「スコープ」で複雑なことをしている場合は、クラスメソッドを使用することを好みます。お気づきのように、カウントなどを返す必要がある場合は、クラス メソッドを使用します。

于 2011-05-05T15:00:21.957 に答える
15

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

クラスメソッドでは、メソッド呼び出し時にコードが実行されるためです。

于 2013-11-07T11:28:57.733 に答える