Problema 1
Vamos considerar o exemplo básico:
class Post < ActiveRecord::Base
default_scope { where(published: true) }
end
A motivação para fazer o padrão published: true
é garantir que você seja explícito quando desejar mostrar postagens (privadas) não publicadas. Por enquanto, tudo bem.
2.1.1 :001 > Post.all
Post Load (0.2ms) SELECT "posts".* FROM "posts" WHERE "posts"."published" = 't'
Bem, isso é praticamente o que esperamos. Agora vamos tentar:
2.1.1 :004 > Post.new
=> #<Post id: nil, title: nil, published: true, created_at: nil, updated_at: nil>
E aí temos o primeiro grande problema com o escopo padrão:
=> default_scope afetará a inicialização do modelo
Em uma instância recém-criada de um modelo desse tipo, default_scope
isso será refletido. Portanto, embora você queira ter certeza de não listar postagens não publicadas por acaso, agora você está criando postagens publicadas por padrão.
Problema 2
Considere um exemplo mais elaborado:
class Post < ActiveRecord::Base
default_scope { where(published: true) }
belongs_to :user
end
class User < ActiveRecord::Base
has_many :posts
end
Permite obter as primeiras postagens de usuários:
2.1.1 :001 > User.first.posts
Post Load (0.3ms) SELECT "posts".* FROM "posts" WHERE "posts"."published" = 't' AND "posts"."user_id" = ? [["user_id", 1]]
Isso parece esperado (certifique-se de rolar todo o caminho para a direita para ver a parte sobre o user_id).
Agora queremos obter a lista de todas as postagens - inclusive não publicadas - para a visualização do usuário conectado. Você perceberá que precisa "substituir" ou "desfazer" o efeito de default_scope
. Depois de um rápido google, você provavelmente descobrirá unscoped
. Veja o que acontece a seguir:
2.1.1 :002 > User.first.posts.unscoped
Post Load (0.2ms) SELECT "posts".* FROM "posts"
=> Sem escopo remove TODOS os escopos que normalmente se aplicam ao seu select, incluindo (mas não limitado a) associações.
Existem várias maneiras de substituir os diferentes efeitos do default_scope
. Conseguir isso direito fica complicado muito rapidamente e eu diria que não usar o default_scope
em primeiro lugar, seria uma escolha mais segura.
unscoped
invés dodefault_scope
problema # 2default_scope
é quando você quer algo a ser resolvido:default_scope { order(:name) }
.Outro motivo para não usar
default_scope
é quando você está excluindo uma instância de um modelo que tem uma relação de 1 para muitos com odefault_scope
modeloConsidere, por exemplo:
A chamada
user.destroy
excluirá todas as postagens que sãopublished
, mas não excluirá as postagens que sãounpublished
. Portanto, o banco de dados lançará uma violação de chave estrangeira porque contém registros que referenciam o usuário que você deseja remover.fonte
O default_scope é frequentemente recomendado, porque às vezes é usado incorretamente para limitar o conjunto de resultados. Um bom uso do default_scope é solicitar o conjunto de resultados.
Eu ficaria longe de usar o
where
default_scope e criaria um escopo para isso.fonte
default_scope
único contenhaorder
. Esse comportamentounscoped
é bastante inesperado.Para mim não é uma má idéia, mas deve ser usada com cautela !. Há um caso em que eu sempre quis ocultar certos registros quando um campo é definido.
default_scope
deve corresponder ao valor padrão do banco de dados (por exemplo{ where(hidden_id: nil) }
:)unscoped
método que evitarádefault_scope
Então, vai depender e as reais necessidades.
fonte
Eu só acho
default_scope
que é útil apenas na ordenação de alguns parâmetros para estarasc
oudesc
ordem em todas as situações. Caso contrário, eu evito isso como uma pragafonte