Problème 1
Prenons l'exemple de base:
class Post < ActiveRecord::Base
default_scope { where(published: true) }
end
La motivation pour faire la valeur par défaut published: true
, peut être de vous assurer que vous devez être explicite lorsque vous souhaitez afficher des messages non publiés (privés). Jusqu'ici tout va bien.
2.1.1 :001 > Post.all
Post Load (0.2ms) SELECT "posts".* FROM "posts" WHERE "posts"."published" = 't'
Eh bien, c'est à peu près ce à quoi nous nous attendons. Essayons maintenant:
2.1.1 :004 > Post.new
=> #<Post id: nil, title: nil, published: true, created_at: nil, updated_at: nil>
Et là, nous avons le premier gros problème avec la portée par défaut:
=> default_scope affectera l'initialisation de votre modèle
Dans une instance nouvellement créée d'un tel modèle, le default_scope
sera reflété. Ainsi, bien que vous ayez peut-être voulu être sûr de ne pas lister les articles non publiés par hasard, vous créez maintenant des articles publiés par défaut.
Problème 2
Prenons un exemple plus élaboré:
class Post < ActiveRecord::Base
default_scope { where(published: true) }
belongs_to :user
end
class User < ActiveRecord::Base
has_many :posts
end
Permet d'obtenir les premiers messages des utilisateurs:
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]]
Cela ressemble à ce que vous attendez (assurez-vous de faire défiler tout le chemin vers la droite pour voir la partie concernant le user_id).
Maintenant, nous voulons obtenir la liste de tous les messages - non publiés inclus - par exemple pour la vue de l'utilisateur connecté. Vous réaliserez que vous devez «écraser» ou «annuler» l'effet de default_scope
. Après un rapide google, vous découvrirez probablement unscoped
. Voyez ce qui se passe ensuite:
2.1.1 :002 > User.first.posts.unscoped
Post Load (0.2ms) SELECT "posts".* FROM "posts"
=> Unscoped supprime TOUTES les étendues qui pourraient normalement s'appliquer à votre sélection, y compris (mais sans s'y limiter) les associations.
Il existe plusieurs façons d'écraser les différents effets du default_scope
. Obtenir ce droit se complique très rapidement et je dirais que ne pas utiliser le, default_scope
en premier lieu, serait un choix plus sûr.
unscoped
plutôt quedefault_scope
dans le problème n ° 2default_scope
c'est quand vous voulez quelque chose à trier:default_scope { order(:name) }
.Une autre raison de ne pas utiliser
default_scope
est lorsque vous supprimez une instance d'un modèle qui a une relation 1 à plusieurs avec ledefault_scope
modèleConsidérez par exemple:
L'appel
user.destroy
supprimera tous les messagespublished
, mais ne supprimera pas les messages qui le sontunpublished
. Par conséquent, la base de données lèvera une violation de clé étrangère car elle contient des enregistrements faisant référence à l'utilisateur que vous souhaitez supprimer.la source
default_scope est souvent déconseillé car il est parfois utilisé de manière incorrecte pour limiter le jeu de résultats. Une bonne utilisation de default_scope est d'ordonner le jeu de résultats.
Je resterais loin d'utiliser
where
dans default_scope et créerais plutôt une portée pour cela.la source
default_scope
seule contientorder
. Ce comportement deunscoped
est assez inattendu.Pour moi n'est pas une mauvaise idée mais doit être utilisé avec prudence !. Il y a un cas où j'ai toujours voulu masquer certains enregistrements lorsqu'un champ est défini.
default_scope
doit correspondre à la valeur par défaut de la base de données (par exemple:{ where(hidden_id: nil) }
)unscoped
méthode qui vous éviteradefault_scope
Cela dépendra donc des besoins réels.
la source
Je ne trouve
default_scope
utile que pour ordonner que certains paramètres soient dansasc
ou endesc
ordre dans toutes les situations. Sinon je l'évite comme la pestela source