Visão geral
Neste guia, você pode aprender como implementar escopos em seus modelos Mongoid. Os escopos fornecem uma maneira conveniente de reutilizar critérios de filtro comuns. Para saber mais sobre como criar critérios de filtro, consulte o guia Especificar uma query de documento.
Você pode implementar escopos em seu aplicação para reduzir o código repetido se estiver aplicando os mesmos critérios à maioria das queries.
Escopos nomeados
Escopos nomeados são critérios definidos na carga de classe que são referenciados por um nome fornecido. Semelhantes aos critérios de filtro, eles são carregados preguiçosamente e acorrentados.
Este exemplo define um modelo Band
que inclui os seguintes escopos nomeados:
japanese
: corresponde a documentos em que o valor do campocountry
é"Japan"
rock
: corresponde a documentos em que o valor do campogenre
inclui"rock"
class Band include Mongoid::Document field :country, type: String field :genres, type: Array scope :japanese, ->{ where(country: "Japan") } scope :rock, ->{ where(:genres.in => [ "rock" ]) } end
Em seguida, você pode consultar usando os escopos nomeados. A query a seguir usa os escopos nomeados para corresponder a documentos nos quais o valor do campo country
é "Japan"
e o valor do campo genre
inclui "rock"
:
Band.japanese.rock
Escopo avançado
Você pode definir Proc
objetos e blocos em escopos nomeados para que eles aceitem parâmetros e estendam a funcionalidade.
Este exemplo define um modelo Band
que inclui o escopo based_in
, que corresponde a documentos nos quais o valor do campo country
é o valor especificado passado como um parâmetro:
class Band include Mongoid::Document field :name, type: String field :country, type: String scope :based_in, ->(country){ where(country: country) } end
Em seguida, faça uma query usando o escopo based_in
, conforme mostrado no código a seguir:
Band.based_in("Spain")
O Mongoid permite definir um escopo que sombreia um método de classe existente, conforme mostrado no exemplo a seguir:
class Band include Mongoid::Document def self.on_tour true end scope :on_tour, ->{ where(on_tour: true) } end
Você pode direcionar o Mongoid para gerar um erro quando um escopo substituir um método de classe existente definindo a opção de configuração scope_overwrite_exception
como true
.
Para saber mais sobre essa configuração, consulte o guia Configuração do aplicativo.
Escopos padrão
Os escopos padrão são úteis para casos em que você aplica os mesmos critérios à maioria das queries. Ao definir um escopo padrão, você especifica estes critérios como padrão para quaisquer queries que utilizem o modelo. Os escopos padrão retornam objetos Criteria
.
Para criar um escopo padrão, você deve definir o método default_scope
em sua classe de modelo.
O seguinte código define o método default_scope
no modelo Band
para recuperar somente documentos em que o valor de campo active
seja true
:
class Band include Mongoid::Document field :name, type: String field :active, type: Boolean default_scope -> { where(active: true) } end
Em seguida, qualquer query no pré-filtro do modelo Band
para documentos nos quais o valor active
é true
.
Inicialização do campo
A especificação de um escopo padrão inicializa os campos de novos modelos para os valores fornecidos no escopo padrão se esses valores forem literais, como valores booleanos ou inteiros.
Observação
Conflitos de campo e escopo
Se você fornecer um valor padrão em uma definição de campo e no escopo padrão, o valor no escopo padrão terá precedência, como mostrado no exemplo a seguir:
class Band include Mongoid::Document field :name, type: String field :on_tour, type: Boolean, default: true default_scope ->{ where(on_tour: false) } end # Creates a new Band instance in which "on_tour" is "false" Band.new
Não recomendamos usar notação de ponto para fazer referência a campos aninhados em escopos padrão. Isso pode direcionar o Mongoid a inicializar campos inesperados em novos modelos.
Por exemplo, se você definir um escopo padrão que referencia o campo tour.year
, um novo modelo será inicializado com o campo tour.year
em vez de um campo tour
com um objeto aninhado que contém um campo year
.
Ao consultar, o Mongoid interpreta a notação de ponto corretamente e corresponde a documentos nos quais um campo aninhado tem o valor especificado.
Associações
Se você definir um escopo padrão em um modelo que faz parte de uma associação, será necessário recarregar a associação para que o escopo seja reaplicado. Isso é necessário para quando você altera um valor de um documento na associação que afeta sua visibilidade quando o escopo é aplicado.
Este exemplo usa os seguintes modelos:
class Label include Mongoid::Document field :name, type: String embeds_many :bands end class Band include Mongoid::Document field :name, type: String field :active, default: true embedded_in :label default_scope ->{ where(active: true) } end
Suponha que você crie um modelo Label
que contenha uma associação com um Band
no qual o valor de active
é true
. Quando você atualiza o campo active
para false
, o Mongoid ainda o carrega, apesar do escopo padrão. Para visualizar os documentos na associação com o escopo aplicado, você deve chamar o operador reload
.
O seguinte código demonstra esta sequência:
label = Label.new(name: "Hello World Records") band = Band.new(name: "Ghost Mountain") label.bands.push(band) label.bands # Displays the Band because "active" is "true" band.update_attribute(:active, false) # Updates "active" to "false" # Displays the "Ghost Mountain" band label.bands # => {"_id":"...","name":"Ghost Mountain",...} # Won't display "Ghost Mountain" band after reloading label.reload.bands # => nil
ou e nem Comportamento da query
O Mongoid trata os critérios em um escopo padrão da mesma forma que quaisquer outras condições de query. Isso pode levar a um comportamento surpreendente ao usar os métodos or
e nor
.
Os exemplos a seguir demonstram como o Mongoid interpreta queries em modelos com um escopo padrão:
class Band include Mongoid::Document field :name field :touring field :member_count default_scope ->{ where(touring: true) } end # Combines the condition to the default scope with "and" Band.where(name: 'Infected Mushroom') # Interpreted query: # {"touring"=>true, "name"=>"Infected Mushroom"} # Combines the first condition to the default scope with "and" Band.where(name: 'Infected Mushroom').or(member_count: 3) # Interpreted query: # {"$or"=>[{"touring"=>true, "name"=>"Infected Mushroom"}, {"member_count"=>3}]} # Combines the condition to the default scope with "or" Band.or(member_count: 3) # Interpreted query: # {"$or"=>[{"touring"=>true}, {"member_count"=>3}]}
Para saber mais sobre operações lógicas, consulte Operações lógicas no guia Especificar uma query.
Desabilitar escopo ao fazer query
Você pode instruir o Mongoid a não aplicar o escopo padrão usando o operador unscoped
, conforme mostrado nos exemplos a seguir:
# Inline example Band.unscoped.where(name: "Depeche Mode") # Block example Band.unscoped do Band.where(name: "Depeche Mode") end
Substituir escopo padrão em tempo de execução
Você pode usar o método with_scope
para alterar o escopo padrão em um bloco no tempo de execução.
O seguinte modelo define o escopo mexican
nomeado:
class Band include Mongoid::Document field :country, type: String field :genres, type: Array scope :mexican, ->{ where(country: "Mexico") } end
Você pode usar o método with_scope
para definir o escopo nomeado mexican
como o escopo padrão no tempo de execução, conforme mostrado no código a seguir:
Band.with_scope(Band.mexican) do Band.all end
Métodos de classe
O Mongoid trata os métodos de classe que retornam objetos Criteria
como escopos. Você pode fazer query usando esses métodos de classe , como mostrado no exemplo a seguir:
class Band include Mongoid::Document field :name, type: String field :touring, type: Boolean, default: true def self.touring where(touring: true) end end Band.touring
Informações adicionais
Para saber mais sobre como personalizar seus modelos Mongoid, consulte os guias Modele seus dados .