Problema 1
Consideremos el ejemplo básico:
class Post < ActiveRecord::Base
default_scope { where(published: true) }
end
La motivación para establecer el valor predeterminado published: true
podría ser asegurarse de tener que ser explícito cuando desee mostrar publicaciones no publicadas (privadas). Hasta aquí todo bien.
2.1.1 :001 > Post.all
Post Load (0.2ms) SELECT "posts".* FROM "posts" WHERE "posts"."published" = 't'
Bueno, esto es más o menos lo que esperamos. Ahora intentemos:
2.1.1 :004 > Post.new
=> #<Post id: nil, title: nil, published: true, created_at: nil, updated_at: nil>
Y ahí tenemos el primer gran problema con el alcance predeterminado:
=> default_scope afectará la inicialización de su modelo
En una instancia recién creada de dicho modelo, default_scope
se reflejará. Entonces, si bien es posible que haya querido asegurarse de no enumerar publicaciones no publicadas por casualidad, ahora está creando las publicadas de forma predeterminada.
Problema 2
Considere un ejemplo más elaborado:
class Post < ActiveRecord::Base
default_scope { where(published: true) }
belongs_to :user
end
class User < ActiveRecord::Base
has_many :posts
end
Permite obtener las primeras publicaciones de los usuarios:
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]]
Esto se ve como se esperaba (asegúrese de desplazarse completamente hacia la derecha para ver la parte sobre user_id).
Ahora queremos obtener la lista de todas las publicaciones, incluidas las no publicadas, por ejemplo, para la vista del usuario conectado. Te darás cuenta de que tienes que 'sobrescribir' o 'deshacer' el efecto de default_scope
. Después de un rápido google, es probable que lo descubras unscoped
. Mira lo que pasa después:
2.1.1 :002 > User.first.posts.unscoped
Post Load (0.2ms) SELECT "posts".* FROM "posts"
=> Sin ámbito elimina TODOS los ámbitos que normalmente podrían aplicarse a su selección, incluidas (entre otras) las asociaciones.
Hay varias formas de sobrescribir los diferentes efectos de default_scope
. Hacer eso bien se complica muy rápidamente y argumentaría que no usar el default_scope
en primer lugar, sería una opción más segura.
unscoped
lugar deldefault_scope
problema n. ° 2default_scope
es cuando se quiere algo que debe clasificarse:default_scope { order(:name) }
.Otra razón para no usar
default_scope
es cuando está eliminando una instancia de un modelo que tiene una relación de 1 a muchos con eldefault_scope
modeloConsidere por ejemplo:
Las llamadas
user.destroy
eliminarán todas las publicaciones que sonpublished
, pero no eliminarán las publicaciones que sí lo seanunpublished
. Por lo tanto, la base de datos arrojará una violación de clave foránea porque contiene registros que hacen referencia al usuario que desea eliminar.fuente
default_scope a menudo se recomienda contra porque a veces se usa incorrectamente para limitar el conjunto de resultados. Un buen uso de default_scope es ordenar el conjunto de resultados.
Me mantendría alejado del uso
where
en default_scope y más bien crearía un alcance para eso.fuente
default_scope
único contieneorder
. Este comportamiento deunscoped
es bastante inesperado.Para mí no es una mala idea, ¡ pero debe usarse con precaución! Hay un caso en el que siempre quise ocultar ciertos registros cuando se establece un campo.
default_scope
debe coincidir con el valor predeterminado DB (por ejemplo:{ where(hidden_id: nil) }
)unscoped
método que evitará sudefault_scope
Entonces dependerá y las necesidades reales.
fuente
Sólo encuentro
default_scope
para ser útil sólo en ordenar algunos parámetros para estar enasc
odesc
orden en toda situación. De lo contrario lo evito como pestefuente