web-dev-qa-db-fra.com

Actioniverecord Rails 3 Portée VS Méthode de classe

Je suis nouveau dans la nouvelle interface de requête d'ActiveRecord, je tiens toujours à trouver des choses.

J'espérais que quelqu'un puisse expliquer la différence entre l'utilisation d'un scope dans un modèle Activerecord et d'utiliser simplement une méthode de classe (c'est-à-dire self.some_method)

D'après ce que je peux rassembler, une portée est toujours censée renvoyer une relation, alors qu'une méthode de classe n'a pas nécessairement besoin. Est-ce vrai?

Par exemple, je pensais qu'il serait logique de faire quelque chose comme:

class Person
  scope :grouped_counts, group(:name).count
end

Mais cela ne fonctionne pas. Je reçois cette erreur:

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

Il fonctionne cependant comme une méthode de classe

def self.grouped_counts
  group(:name).count
end

Je suis intéressé de connaître les pensées des peuples sur quand utiliser des étendues et quand utiliser des méthodes de classe. Suis-je correct pour supposer qu'une portée doit toujours renvoyer une relation, mais une méthode de classe peut retourner ce qu'il veut?

50
brad

AS Dylan fait allusion à sa réponse, une différence entre la portée et la méthode de la classe est que les scopes sont évalués lorsque la classe est chargée. Cela peut conduire à un résultat inattendu.

Par exemple,

class Post < ActiveRecord::Base
    scope :published_earlier, where('published_at < ?', Date.today)
end

est sujette à l'erreur. La bonne façon est d'utiliser une lambda

class Post < ActiveRecord::Base
    scope :published_earlier, -> { where('published_at < ?', Date.today) }
end

Le bloc Lambda est évalué paresseusement. Donc, date.today est exécutée lorsque vous appelez la portée, pas lorsque la classe est évaluée.

Si vous utilisez une méthode de classe, vous n'avez pas besoin d'utiliser Lambda.

class Post < ActiveRecord::Base
    def self.published_earlier
        where('published_at < ?', Date.today)
    end
end

Parce que avec la méthode de classe, le code est exécuté au moment de l'appel de la méthode.

12
Zack Xu