Supposons que vous ayez un modèle avec une relation un-à-un-à-plusieurs comme illustré ci-dessous.
class User
has_one :examinee
end
class Examinee
belongs_to :user
has_many :tests
end
class Test
belongs_to :examinee
end
Alors, comment l'implémentez-vous lorsque vous souhaitez obtenir le modèle de test pertinent à partir du modèle utilisateur?
Il existe différentes façons de le faire, mais je pense que vous utilisez souvent la fonction pratique «déléguer» d'ActiveRecord ou «has_many-through». Les deux peuvent réaliser ce que vous voulez faire, mais les requêtes émises sont légèrement différentes, je vais donc les présenter.
delegate
Vous pouvez utiliser déléguer pour déléguer une méthode à une autre classe. Consultez le Guide des rails pour plus de détails. 3.4.1 delegate
Dans ce cas, procédez comme suit.
app/models/user.rb
delegate :tests, to: :examinee
Une fois exécutées, deux requêtes seront émises comme indiqué ci-dessous. Le comportement consiste à obtenir d'abord le candidat de la destination de délégation (première requête), puis à exécuter examinere.tests (deuxième requête).
irb> user.tests
Examinee Load SELECT `examinees`.* FROM `examinees` WHERE `examinees`.`user_id` = 1 LIMIT 1
Test Load SELECT `tests`.* FROM `tests` WHERE `tests`.`examinee_id` = 1
has_many-through
has_many-through est souvent utilisé dans les cas plusieurs-à-plusieurs, mais il peut également être utilisé dans les cas un-à-plusieurs comme celui-ci.
Consultez le Guide des rails pour plus de détails. 2.4 has_many: par association
Dans ce cas, procédez comme suit.
app/models/user.rb
has_many :tests, through: :examinee
Une fois exécutée, une requête sera émise comme indiqué ci-dessous. Dans ce cas, une seule requête jointe sera émise. Considérant que cette fonction est implémentée de manière à correspondre à plusieurs-à-plusieurs, vous pouvez comprendre qu'elle est acquise par jointure car elle ne peut pas être acquise efficacement en deux étapes comme deletgate.
irb> user.tests
Test Load SELECT `tests`.* FROM `tests` INNER JOIN `examinees` ON `tests`.`examinee_id` = `examinees`.`id` WHERE `examinees`.`user_id` = 1
S'il vaut mieux l'obtenir avec 2 requêtes ou 1 requête jointe dépend de l'environnement d'exécution, il n'est donc pas possible de juger si c'est bon ou mauvais. Dans la plupart des cas, peu importe celui que vous écrivez, donc peu importe celui que vous écrivez.
Cependant, même s'il semble faire la même chose du point de vue de la boîte noire, les requêtes émises en interne peuvent être différentes comme cette fois. Parfois, il serait intéressant de vérifier ces petites différences lorsque l'on considère l'origine et le but de la fonction.
Recommended Posts