has_many :through : Comment accédez-vous à la table de jointure attributs?
J'ai les modèles suivants dans les Rails 4 avec un simple has_many :par l'association:
class Model < ActiveRecord::Base
has_many :model_options
has_many :options, through: :model_options
end
class Option < ActiveRecord::Base
has_many :model_options
has_many :models, through: :model_options
end
class ModelOption < ActiveRecord::Base
belongs_to :model
belongs_to :option
end
Je veux être en mesure d'effectuer une itération sur un Modèle de l'instance Options:
model = Model.find.first
model.options.each {}
et l'accès aux attributs sur la table de jointure.
Dans Rails 3, vous pourriez faire ceci:
class Model < ActiveRecord::Base
has_many :model_options
has_many :options, through: :model_options , select: 'options.*, model_options.*'
end
Mais de sélectionner: est obsolète et ce produit une dépréciation d'avertissement.
Cela dit, le SQL généré contient la table de liaison de données:
SELECT options.*, model_options.* FROM "options"
INNER JOIN "model_options" ON "options"."id" = "model_options"."option_id"
WHERE "model_options"."model_id" = $1 ORDER BY "options".name ASC [["model_id", 1]]
Mais la collection retournée par l'AR du modèle.options supprime le lien de la table de données.
Pour supprimer les désapprobations avertissement dans les Rails 4, et encore produire le même SQL, j'ai fait ça:
class Model < ActiveRecord::Base
has_many :model_options
has_many :options, -> { select('options.*, model_options.*') }, through: :model_options
end
Ainsi, la requête est correcte, mais j'ai du mal à trouver le bon moyen pour accéder à la table de liaison de données.
J'ai essayé de différentes façons:
model options
model.options.joins(:model_options)
model.options.select('options.*, model_options.*')
model.model_options.joins(:option)
...
Aucun inclure la jointure de la table de données.
Grâce.
- Ne Optionmodèle modèle faire quelque chose de plus à l'extérieur de deux identifiants?
- Oui, Optionmodèle a un certain nombre d'attributs sur elle. Par exemple, le prix, d'où une option est le prix variera selon le modèle.
- J'ai le même problème. Comment avez-vous le résoudre?
- J'ai trouvé que la table de jointure attributs sont accessibles de manière transparente comme
model.price
(oùprice
comme l'attribut de la Optionmodèle) après avoir spécifié lehas_many ... select()
déclaration à inclure.
Vous devez vous connecter pour publier un commentaire.
La réponse peut être différente sur ce que vous voulez atteindre. Voulez-vous récupérer les attributs ou les utiliser pour d'interrogation ?
Résultats de chargement
ActiveRecord est sur le mappage des lignes de la table des objets, de sorte que vous ne pouvez pas avoir les attributs d'un objet dans un autre.
Laisser utiliser un exemple plus concret : Il y a la Maison, la Personne et le Chien. Une personne belongs_to maison. Un chien belongs_to une personne. Une maison a beaucoup de gens. Une maison a beaucoup de chiens à travers les gens.
Maintenant, si vous devez récupérer un chien, vous ne vous attendez pas à avoir personne attributs en elle. Il ne serait pas logique d'avoir un car_id attribut chien attributs.
Cela étant dit, ce n'est pas un problème : ce que vous voulez vraiment, je pense, est d'éviter de faire beaucoup de requêtes db, ici. Rails a votre retour sur ce :
Edit : Il se comporte comme cela dans la console. En fait le code de l'application, la requête sql sera tiré sur la deuxième commande, parce que d'abord on n'a pas utiliser le résultat (la requête sql est déclenché uniquement lorsque nous avons besoin de ses résultats). Mais cela n'y change rien : il n'a tiré qu'une seule fois.
#includes
est juste que : le chargement de tous les attributs d'une table étrangère dans le jeu de résultats. Ensuite, tout est mappé à avoir une véritable représentation orientée objet.À l'aide d'attributs de requête
Si vous voulez faire de requête basée sur les deux Options et ModelOptions, vous aurez à utiliser
#references
. Disons que votre Optionmodèle a unactive
attribut :Conclusion
#includes
va charger toutes les lignes dans le résultat du jeu de sorte que vous pouvez les utiliser ultérieurement, sans autre interrogation de la base de données.#references
vous permettra également d'utiliser la table dans les requêtes.En aucun cas, vous avez un objet contenant des données à partir d'un autre modèle, mais c'est une bonne chose.
options = model.options.includes(:model_options)
Puis options.to_sql:=> "SELECT "options".* FROM "options" INNER JOIN "model_options" ON "options"."id" = "model_options"."option_id" WHERE "model_options"."model_id" = $1 ORDER BY "options".name ASC"
Donc, ce n'est pas le retour de la model_options attributs. Notez, cependant, que je peux faire, dire:model.options.where(model_options: {price: 10})
et il renvoie l'option appropriée. Mais encore AR ne retourne pas le model_options de données.#to_sql
montre, car il n'affiche que la première requête s'il y a plusieurs. Pour voir ce qui est en effet exécuter, le feu de la requête enrails console
.user
has_many :folders, through: :folder_permissions
etfolder
has_many :users, through :folder_permissions
. On attend les autorisations de dossier à un attribut d'un dossier, mais dans une association habtm il fait plus de sens pour stocker ces autorisations dans la jointure du modèle. Je voudrais savoir comment faire cela dans les rails 4 aussi.<user>.items.custom_scope.references(:join_table)
il va essayer d'exécuter custom_scope sur le dessus deItem::ActiveRecord_Associations_CollectionProxy
.Comme dit Olivier, vous avez très envie de charge de l'association.
Pour une raison que l'association ne retourne pas le seul model_options de données lorsque vous utilisez comprend.
Il fonctionne pour moi, quand je force AR de faire une seule requête avec eager_load.
votre modifier votre modèle :
Peut maintenant accéder à tous les attribut de l'adhésion ("model_options") de la table et des "options" de la table, comme ceci:
001 >>model = modèle.première
002 >>le modèle.all_options
Plus: https://blog.codedge.io/rails-join-table-with-extra-attributes/