Frage

Ich bin neu in der neuen Abfrageoberfläche von ActiveRecord, daher finde ich immer noch Dinge heraus.

Ich hatte gehofft, jemand könnte den Unterschied zwischen der Verwendung eines scopes in einem ActiveRecord-Modell und der Verwendung einer Klassenmethode (dh self.some_method) erklären

Soweit ich das beurteilen kann, wird von einem Bereich immer erwartet, dass er eine Beziehung zurückgibt, während dies bei einer Klassenmethode nicht unbedingt der Fall sein muss.Ist das wahr?

Zum Beispiel dachte ich, es wäre sinnvoll, etwas zu tun wie:

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

Aber das funktioniert nicht.Ich erhalte die folgende Fehlermeldung:

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

Es funktioniert jedoch als Klassenmethode

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

Ich bin daran interessiert, die Gedanken der Leute darüber zu kennen, wann Bereiche und wann Klassenmethoden verwendet werden sollen.Habe ich Recht, wenn ich davon ausgehe, dass ein Bereich immer eine Beziehung zurückgeben muss, eine Klassenmethode jedoch alles zurückgeben kann, was sie will?

War es hilfreich?

Lösung

In Rails 2.x gab es einen größeren Unterschied, da named_scopes Ihre Abfragen nicht ausführte (damit Sie sie verketten konnten), während Klassenmethoden die Abfragen im Allgemeinen ausführten (damit Sie sie nicht verketten konnten), es sei denn, Sie manuellhat Ihre Anfrage in einen scoped(...)-Aufruf eingeschlossen.

In Rails 3 gibt alles einen ActiveRecord::Relation zurück, bis Sie die tatsächlichen Ergebnisse benötigen, sodass Bereiche mit Klassenmethoden verkettet werden können und umgekehrt (solange die Klassenmethoden ActiveRecord::Relation-Objekte zurückgeben, nicht irgendeinen anderen Objekttyp (wie eine Zählung)).).

Im Allgemeinen verwende ich scope-Einträge für einfache Einzeiler, um meine Ergebnismenge herauszufiltern.Wenn ich jedoch etwas Kompliziertes in einem "Bereich" mache, der detaillierte Logik, Lambdas, mehrere Zeilen usw. erfordert, bevorzuge ich die Verwendung einer Klassenmethode.Und wie Sie bemerkt haben, verwende ich eine Klassenmethode, wenn ich Zählungen oder ähnliches zurückgeben muss.

Andere Tipps

Wie Dylan in seiner Antwort angedeutet hat, besteht ein Unterschied zwischen Bereich und Klassenmethode darin, dass Bereiche ausgewertet werden, wennDie Klasse wird geladen.Dies kann zu unerwarteten Ergebnissen führen.

Zum Beispiel

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

ist fehleranfällig.Der richtige Weg ist die Verwendung eines Lambda

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

Lambda-Block wird träge ausgewertet.Date.today wird also ausgeführt, wenn Sie den Bereich aufrufen, nicht wenn die Klasse ausgewertet wird.

Wenn Sie eine Klassenmethode verwenden, müssen Sie kein Lambda verwenden.

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

Da bei der Klassenmethode der Code zum Zeitpunkt des Methodenaufrufs ausgeführt wird.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top