Question

Je suis nouveau dans la nouvelle interface de requête d'ACTIVERECORD, donc je trouve toujours les choses.

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

D'après ce que je peux rassembler, une portée devrait toujours retourner une relation, alors qu'une méthode de classe ne doit pas nécessairement à le faire. Est-ce vrai?

Par exemple, j'ai pensé qu'il serait logique de faire quelque chose comme:

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

Mais cela ne fonctionne pas. J'obtiens 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

Cela fonctionne cependant comme une méthode de classe

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

Je suis intéressé à connaître les réflexions des gens sur le moment d'utiliser des lunettes et quand utiliser les méthodes de classe. Ai-je raison de supposer qu'une portée doit toujours renvoyer une relation, mais une méthode de classe peut renvoyer ce qu'elle veut?

Était-ce utile?

La solution

Il y avait plus de différence dans Rails 2.x, car Named_scopes n'a pas exécuté vos requêtes (afin que vous puissiez les enchaîner), tandis que les méthodes de classe ont généralement exécuté les requêtes (afin que vous ne puissiez pas les enchaîner), sauf si vous avez enveloppé manuellement votre requête dans un scoped(...) appel.

Dans Rails 3, tout renvoie un ActiveRecord::Relation Jusqu'à ce que vous ayez besoin des résultats réels, les lunettes peuvent donc être enchaînées contre les méthodes de classe et vice versa (tant que les méthodes de classe reviennent ActiveRecord::Relation objets, pas un autre type d'objet (comme un compte)).

Généralement, j'utilise scope Entrées pour que les one-liners simples pour filtrer mon ensemble de résultats. Cependant, si je fais quelque chose de compliqué dans une "portée" qui peut nécessiter une logique détaillée, des lambdas, plusieurs lignes, etc., je préfère utiliser une méthode de classe. Et comme vous l'avez attrapé, si j'ai besoin de retourner des comptes ou quelque chose comme ça, j'utilise une méthode de classe.

Autres conseils

Comme Dylan mentionné dans sa réponse, une différence entre la portée et la méthode de la classe est que les portées sont évaluées 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 sujet à l'erreur. La bonne façon est d'utiliser un 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é 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 qu'avec la méthode de classe, le code est exécuté au moment de l'appel de la méthode.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top