Pregunta

Soy nuevo en la nueva interfaz de consulta de ActiveRecord, así que todavía estoy averiguando cosas.

Esperaba que alguien pudiera explicar la diferencia entre usar un scope en un modelo ActiveRecord y simplemente usando un método de clase (es decir self.some_method)

Por lo que puedo deducir, siempre se espera que un alcance devuelva una relación, mientras que un método de clase no necesariamente tiene que hacerlo.¿Es esto cierto?

Por ejemplo, pensé que tendría sentido hacer algo como:

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

Pero esto no funciona.Recibo este error:

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

Sin embargo, funciona como método de clase.

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

Me interesa conocer la opinión de la gente sobre cuándo usar ámbitos y cuándo usar métodos de clase.¿Estoy en lo cierto al suponer que un ámbito siempre debe devolver una relación, pero un método de clase puede devolver lo que quiera?

¿Fue útil?

Solución

Había más diferencia en Rails 2.x, ya que los name_scopes no ejecutaban tus consultas (por lo que podías encadenarlas), mientras que los métodos de clase generalmente ejecutaban las consultas (por lo que no podías encadenarlas), a menos que envolvieras tu consulta manualmente. en un scoped(...) llamar.

En Rails 3, todo devuelve un ActiveRecord::Relation hasta que necesite los resultados reales, por lo que los ámbitos se pueden encadenar contra métodos de clase y viceversa (siempre que los métodos de clase devuelvan ActiveRecord::Relation objetos, no algún otro tipo de objeto (como un recuento)).

Generalmente uso scope entradas de frases ingeniosas simples para filtrar mi conjunto de resultados.Sin embargo, si estoy haciendo algo complicado en un "alcance" que puede requerir lógica detallada, lambdas, líneas múltiples, etc., prefiero usar un método de clase.Y como habrás comprendido, si necesito devolver recuentos o algo así, uso un método de clase.

Otros consejos

Como Dylan Aludido en su respuesta, una diferencia entre el alcance y el método de clase es que los alcances se evalúan cuando se carga la clase.Esto puede llevar a resultados inesperados.

Por ejemplo,

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

es propenso a errores.La forma correcta es usar una lambda.

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

El bloque lambda se evalúa de forma perezosa.Así Date.today se ejecuta cuando se llama el alcance, no cuando se evalúa la clase.

Si usa un método de clase, no necesita usar lambda.

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

Porque con el método de clase, el código se ejecuta en el momento de la llamada al método.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top