Pergunta

Eu sou novo na nova interface de consulta do ActiveRecord, então ainda estou descobrindo algumas coisas.

Eu esperava que alguém pudesse explicar a diferença entre usar um scope em um modelo ActiveRecord e apenas usar um método de classe (ou seja, self.some_method)

Pelo que pude perceber, sempre se espera que um escopo retorne uma relação, enquanto um método de classe não necessariamente precisa.Isso é verdade?

Por exemplo, achei que faria sentido fazer algo como:

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

Mas isso não funciona.Eu recebo este erro:

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

No entanto, funciona como um método de classe

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

Estou interessado em saber a opinião das pessoas sobre quando usar escopos e quando usar métodos de classe.Estou correto ao presumir que um escopo deve sempre retornar uma relação, mas um método de classe pode retornar o que quiser?

Foi útil?

Solução

Havia mais uma diferença no Rails 2.x, já que named_scopes não executava suas consultas (para que você pudesse encadear), enquanto os métodos de classe geralmente executavam as consultas (para que você não pudesse encadear), a menos que você manualmenteenvolveu sua consulta em uma chamada scoped(...).

No Rails 3, tudo retorna um ActiveRecord::Relation até que você precise dos resultados reais, então escopos podem ser encadeados contra métodos de classe e vice-versa (contanto que os métodos de classe retornem objetos ActiveRecord::Relation, e não algum outro tipo de objeto (como uma contagem)).

Geralmente, eu uso entradas scope para linhas simples simples para filtrar meu conjunto de resultados.No entanto, se estou fazendo algo complicado em um "escopo" que pode exigir lógica detalhada, lambdas, várias linhas, etc., prefiro usar um método de classe.E como você percebeu, se eu precisar retornar contagens ou algo parecido, eu uso um método de classe.

Outras dicas

Como Dylan aludiu em sua resposta, uma diferença entre escopo e método de classe é que os escopos são avaliados quandoa classe está carregada.Isso pode levar a resultados inesperados.

Por exemplo,

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

está sujeito a erros.A maneira correta é usar um lambda

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

O bloco lambda é avaliado lentamente.Então Date.today é executado quando você chama o escopo, não quando a classe é avaliada.

Se você usar um método de classe, não precisará usar lambda.

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

Porque com o método de classe, o código é executado no momento da chamada do método.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top