web-dev-qa-db-fra.com

Comment utiliser unscoped sur les relations associées dans Rails3?

J'ai une portée par défaut sur les produits en raison de contraintes de sécurité de l'information.

class Product < ActiveRecord::Base
  has_many :photos

  default_scope where('visible = 1')
end

Cependant, dans mon modèle photo associé, je dois également trouver des produits qui ne devraient pas être visibles.

class Photo < ActiveRecord::Base
  belongs_to :product
end

my_photo.product

Dans d'autres cas, je peux utiliser nscoped afin de contourner le default_scope, par ex. dans Product.unscoped.find_by_title('abc'). Pourtant:

Comment supprimer la portée lors de l'utilisation des associations d'un enregistrement?

my_photo.unscoped.product N'a pas de sens car my_photo n'a pas de méthode appelée unscoped. my_photo.product.unscoped N'a pas non plus de sens car my_photo.product Peut déjà être nul.

62
crispy

Oh. Je me suis trompé. Je pensais que ce qui suit ne fonctionnerait pas ... mais cela fonctionne:

Product.unscoped do
  my_photo.product
end

Notez que vous devez appeler unscoped sur le modèle avec le default_scope qui devrait être contourné.

De plus, l'héritage doit être respecté. Si tu as class InsuranceProduct < Productet class FinancialProduct < Product et un default_scope dans Product, les deux combinaisons suivantes fonctionneront:

InsuranceProduct.unscoped do
  my_record.insurance_products
end

FinancialProduct.unscoped do
  my_record.financial_products
end

Product.unscoped do
  my_record.products
end

Cependant, ce qui suit ne fonctionnera pas bien que la portée soit définie dans Product:

Product.unscoped do
  my_record.financial_products
end

Je suppose que c'est une autre bizarrerie de STI dans Ruby/Rails.

62
crispy

Une autre option consiste à remplacer la méthode getter et à annuler la super-étendue:

class Photo < ActiveRecord::Base
  belongs_to :product

  def product
    Product.unscoped{ super }
  end
end

Je suis tombé sur la même situation où j'avais un modèle associé qui devait être non délimité, mais dans presque tous les autres cas, il avait besoin de la portée par défaut. Cela devrait vous éviter les appels supplémentaires vers unscoped si vous utilisez le getter d'association à plusieurs endroits.

50
johnmcaliley

Je suis probablement un peu en retard à la fête, mais il y a quelque temps je me suis retrouvé dans la même situation et j'ai écrit un bijou pour le faire facilement: nscoped_associations .

Usage:

belongs_to :user, unscoped: true

Soutien:

  • appartient à
  • en a un
  • a beaucoup

Les associations polymorphes sont également prises en charge.

24
markets

Si vous avez besoin qu'une association spécifique soit toujours non étendue, vous pouvez la retirer lors de la définition de l'association:

belongs_to :product, -> { unscope(where: :visible) }

Pour une raison quelconque, la clé where spécifique ne se chargeait pas correctement pour moi, donc je viens de déloger l'intégralité de where, ce qui est une autre option qui se produit dans mon cas:

belongs_to :product, -> { unscope(:where) }

Les autres réponses méritent également d'être examinées, mais il s'agit d'une autre option pour Rails 4.1+.

6
Chris Peters

Dans Rails 4, vous pouvez utiliser l'association avec une annulation explicite du filtre indésirable, c'est-à-dire my_photo.product.unscope(where: :visible)

5
Kamran

Ce n'est pas sur le sujet principal mais votre problème avec ActiveRecord # devient: Nous (espérons-le) l'avons corrigé avec un initialiseur

 classe ActiveRecord :: Base 
 
 def devient_with_association_cache (klass) 
 est devenu = devient_without_association_cache (klass) 
 est devenu.instance_variable_set ("@ association_cache", @association_cache) 
 est devenu 
 fin 
 alias_method_chain: devient,: association_cache 
 
 fin 

https://Gist.github.com/2478161

1
no-dashes

Nouvelle réponse

Cette question devrait vous aider à comprendre comment contourner la clause where par défaut pour votre association.

Il convient de répéter cependant que si vous devez régulièrement éviter une portée, cela devrait probablement être une valeur par défaut. Créez une portée visible non par défaut et utilisez-la explicitement dans vos associations.

0
noodl