2011-05-05 18 views
50

Soy nuevo en la nueva interfaz de consulta de ActiveRecord, así que todavía estoy averiguando cosas.ActiveRecord Rails 3 scope vs class method

Tenía la esperanza de que alguien podría explicar la diferencia entre usar una scope en un modelo ActiveRecord y simplemente utilizando un método de clase (es decir self.some_method)

De lo que he entendido, un ámbito siempre se espera que regrese 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. Me sale este error:

ArgumentError: Unknown key(s): communicating, failed, matched, unmatched 
    from /Users/bradrobertson/.rvm/gems/[email protected]/gems/activesupport-3.0.5/lib/active_support/core_ext/hash/keys.rb:43:in `assert_valid_keys' 
    from /Users/bradrobertson/.rvm/gems/[email protected]/gems/activerecord-3.0.5/lib/active_record/relation/spawn_methods.rb:110:in `apply_finder_options' 
    from /Users/bradrobertson/.rvm/gems/[email protected]/gems/activerecord-3.0.5/lib/active_record/named_scope.rb:110:in `block in scope' 
    from (irb):48 
    from /Users/bradrobertson/.rvm/gems/[email protected]/gems/railties-3.0.5/lib/rails/commands/console.rb:44:in `start' 
    from /Users/bradrobertson/.rvm/gems/[email protected]/gems/railties-3.0.5/lib/rails/commands/console.rb:8:in `start' 
    from /Users/bradrobertson/.rvm/gems/[email protected]/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, sí funcionan como un método de clase

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

me interesa conocer los pensamientos de la gente sobre cuándo utilizar alcances 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?

Respuesta

81

Hubo una mayor diferencia en Rails 2.x, ya que named_scopes no ejecutó sus consultas (por lo que podría encadenarlas), mientras que los métodos de clase generalmente ejecutaban las consultas (por lo que no podía encadenarlas), a menos que envuelve manualmente su consulta en una llamada scoped(...).

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

En general, utilizo entradas scope para líneas 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 atrapaste, si necesito devolver conteos o algo así, utilizo un método de clase.

+0

genial, gracias por la entrada! – brad

+0

Excelente respuesta. Vea también este artículo: [Los ámbitos nombrados están muertos] (http: //www.railway.at/2010/03/09/named-scopes-are-dead /) – mjnissim

10

Al igual que Dylan aludido en su respuesta, una diferencia entre el alcance y el método de clase es que los ámbitos se evalúan cuando se carga la clase. Esto puede conducir a un resultado inesperado.

Por ejemplo,

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

es propenso a error. La forma correcta es utilizar un lambda

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

El bloque Lambda se evalúa con holgura. Entonces Date.today se ejecuta cuando llama al ámbito, no al cuando se evalúa la clase.

Si usa un método de clase, entonces 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.

+2

Se debe tener en cuenta que en Rails 4 se requiere la forma lambda para todos los ámbitos. – pdobb

Cuestiones relacionadas