O que é scope / named_scope em rails?

105

Recentemente comecei um estágio. Meu empregador usa ruby ​​on rails e freqüentemente encontro uma nova sintaxe que preciso pesquisar para entender. Pesquisei no Google por uma boa explicação sobre named_scope, mas o que descobri até agora são principalmente postagens de blog elogiando isso, em vez de uma definição ou introdução direta.

O que exatamente é named_scope (agora simplesmente chamado de escopo) no Ruby on Rails?

Ziggy
fonte
2
Esta postagem do blog foi inestimável para mim ao aprender escopos nomeados: ryandaigle.com/articles/2008/8/20/…
Peter Brown
@notapatch o link está morto, você tem outro?
mbigras
Ryan Daigle: Escopo nomeado: não é apenas para as condições, você sabe ?: web.archive.org/web/20160306110506/http://…
notapatch

Respostas:

212

Um escopo é um subconjunto de uma coleção. Parece complicado? Não é. Imagina isto:

Você tem usuários. Agora, alguns desses usuários estão inscritos em sua newsletter. Você marcou aqueles que recebem um boletim informativo adicionando um campo ao Banco de dados de usuários (user.subscribed_to_newsletter = true). Naturalmente, às vezes você deseja obter os usuários que estão inscritos no seu boletim informativo.

Você poderia, é claro, sempre fazer isso:

User.where(subscribed_to_newsletter: true).each do #something

Em vez de sempre escrever isso, você poderia, entretanto, fazer algo assim.

#File: users.rb
class User < ActiveRecord::Base
  scope :newsletter, where(subscribed_to_newsletter: true)
  #yada yada
end

Se você estiver usando Rails 4 ou mais recente , faça o seguinte:

#File: users.rb
class User < ActiveRecord::Base
  scope :newsletter, -> { where(subscribed_to_newsletter: true) }
  #yada yada
end

Isso permite que você acesse seus assinantes simplesmente fazendo o seguinte:

User.newsletter.each do #something

Este é um exemplo muito simples, mas em geral os escopos podem ser ferramentas muito poderosas para facilitar o seu trabalho.

Confira este link: Descrição da API

Michael Schäfermeyer
fonte
7
Posso perguntar quais são as vantagens disso em relação a, digamos, definir um método na classe de usuário chamado 'assinantesUsuários'? por exemplo, 'def self.subscribedUsers self.where (: subscribed_to_newsletter => true) end
redroot
3
@redroot a vantagem é que a scopesintaxe é muito mais limpa, você obtém o mesmo resultado, mas com apenas uma linha
Aldo 'xoen' Giambelluca
9
@redroot Costumava haver uma grande vantagem de eficiência, pois os escopos consultavam o banco de dados preguiçosamente, enquanto os métodos o faziam avidamente. No Rails 3, os métodos também ficaram preguiçosos, então agora a diferença é mais sintática. Fonte
evanrmurphy
O link do documento da API está quebrado, atualize api.rubyonrails.org/classes/ActiveRecord/Scoping/Named/…
Lohith MV
Também permite o uso de link de
Benjineer
34

O escopo no registro ativo é como os métodos de classe, mas eles retornam o objeto Relation, o que significa que você pode chamar outro escopo ou método de consulta do registro ativo nele.

Por exemplo, se você tiver um modelo Zombie (tabela de zumbis) com os métodos de escopo mencionados abaixo,

class Zombie
  scope :rotting, -> { where(rotting: true) }
  scope :fresh, -> { where('age < ?', 25) }
  scope :recent, -> { order(created_at: :desc) }
end

E você liga

Zombie.rotting.fresh.recent.limit(3)

Isso se traduz no seguinte em SQL,

select "zombies.*" from "zombies" where "zombies"."rotting" = 't' and (age<20) order by create_at desc limit 3

O exemplo acima é baseado na sintaxe do rails 4

Akshatha
fonte
Não consigo encontrar um exemplo de pedido (: created_at,: desc) em qualquer documentação. É possível que você quis dizer scope :recent, -> { order(created_at: :desc) }? apidock.com/rails/v4.2.9/ActiveRecord/QueryMethods/order
notapatch
7

A melhor maneira de entender os detalhes é consultar a documentação da API.

Você obterá os detalhes completos e as maneiras como podemos usar escopos.

Documentação de escopo da API

123
fonte
7

Os escopos nada mais são do que métodos de classe.

Por que usá-los?

O escopo permite que você especifique consultas comumente usadas (pode ser considerado como um atalho para consultas longas ou usadas com mais frequência) que podem ser referenciadas como chamadas de método nos objetos de associação ou modelos. Com esses escopos, você pode usar todos os métodos cobertos anteriormente, como onde, junta e inclui. Todos os métodos de escopo retornarão um objeto ActiveRecord :: Relation que permitirá que outros métodos (como outros escopos) sejam chamados nele.

Para definir um escopo simples, usamos o método de escopo dentro da classe, passando a consulta que gostaríamos de executar quando este escopo for chamado:

class Article < ActiveRecord::Base
  scope :published, -> { where(published: true) }
end

Isso é exatamente o mesmo que definir um método de classe, e o que você usa é uma questão de preferência pessoal:

class Article < ActiveRecord::Base
  def self.published
    where(published: true)
  end
end

Siga o seguinte link para uma descrição completa com exemplo. Eu espero que isso te ajude.

http://guides.rubyonrails.org/active_record_querying.html

Imran Ahmad
fonte
3
Não é exatamente o mesmo que definir um método de classe . Os métodos de classe retornam nilem alguns casos e, portanto, não podem ser encadeados em certas condições.
Arslan Ali
1
  • Imagine que você tem um modelo: Pessoa .

Agora imagine você:

  • quero todas as pessoas no mundo que têm cabelo vermelho.
  • quero todas as pessoas no mundo que jogam críquete

Você pode obter essas classes específicas de pessoas usando um escopo!

Person.red_hair.cricket ## finds all people with red hair who play cricket
Person.red_hair ## finds all people with red hair
Person.cricket ## finds all people who play cricket.

Agora não foi tão difícil, foi?

BKSpurgeon
fonte