Domanda

Sono nuovo nella nuova interfaccia di query di ActiveRecord, quindi sto ancora cercando di capire le cose.

Speravo che qualcuno potesse spiegare la differenza tra l'utilizzo di un scope in un modello ActiveRecord e il semplice utilizzo di un metodo di classe (ad esempio self.some_method)

Da quello che posso raccogliere, ci si aspetta sempre che uno scope restituisca una relazione, mentre un metodo di classe non deve necessariamente farlo.È vero?

Ad esempio, ho pensato che avrebbe avuto senso fare qualcosa del tipo:

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

Ma questo non funziona.Ottengo questo errore:

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

Funziona comunque come un metodo di classe

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

Mi interessa conoscere i pensieri delle persone su quando usare gli scope e quando usare i metodi di classe.Ho ragione nel presumere che uno scope debba sempre restituire una relazione, ma un metodo di classe può restituire quello che vuole?

È stato utile?

Soluzione

C'era più differenza in Rails 2.x, dal momento che named_scopes non eseguiva le tue query (quindi puoi concatenarle), mentre i metodi di classe generalmente eseguivano le query (quindi non puoi concatenarle), a meno che tu nonha racchiuso la tua query in una chiamata scoped(...).

In Rails 3, tutto restituisce un ActiveRecord::Relation fino a quando non servono i risultati effettivi, quindi gli ambiti possono essere concatenati con metodi di classe e viceversa (purché i metodi di classe restituiscano oggetti ActiveRecord::Relation, non qualche altro tipo di oggetto (come un conteggio)).

In genere, utilizzo le voci scope per semplici battute per filtrare il mio set di risultati.Tuttavia, se sto facendo qualcosa di complicato in un "ambito" che potrebbe richiedere una logica dettagliata, espressioni lambda, più righe, ecc., Preferisco utilizzare un metodo di classe.E come hai capito, se ho bisogno di restituire conteggi o qualcosa del genere, utilizzo un metodo di classe.

Altri suggerimenti

Come Dylan ha accennato nella sua risposta, una differenza tra l'ambito e il metodo della classe è che gli ambiti vengono valutati quandola classe viene caricata.Ciò potrebbe portare a risultati imprevisti.

Ad esempio,

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

è soggetto a errori.Il modo corretto è usare un lambda

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

Il blocco Lambda viene valutato pigramente.Quindi Date.today viene eseguito quando chiami l'ambito, non quando la classe viene valutata.

Se utilizzi un metodo di classe, non è necessario utilizzare lambda.

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

Perché con il metodo di classe, il codice viene eseguito al momento della chiamata al metodo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top