Rails 4: Comment utiliser includes () avec where () pour récupérer les objets associés
Je ne peux pas comprendre comment utiliser la méthode .where()
pour récupérer les données de modèle associées. Dans cet exemple, Projects appartient aux utilisateurs ...
class Project < ActiveRecord::Base
belongs_to :user
has_many :videos
end
class User < ActiveRecord::Base
has_many :projects
end
class ProjectsController < ApplicationController
def invite
@project = Project.includes([:user]).where( {:hashed_id=>params[:id]} ).first
end
end
Dans App/views/projects/invite.html.erg <%= debug( @project ) %>
renvoie:
--- !Ruby/object:Project
attributes:
id: 22
name: Some Project Name
belongs_to: 1
instructions: Bla bla bla
active: true
max_duration: 2
max_videos:
created_at: 2013-08-26 15:56:50.000000000 Z
updated_at: 2013-08-26 15:56:50.000000000 Z
hashed_id: '1377532589'
Le hachage/tableau utilisateur associé ne doit-il pas être inclus dans cela? Je sais que je pourrais l'ajouter manuellement en appelant un second find
/where
(@project.user = User.where( {:id=>@project.belongs_to}
) Mais cela ne ressemble pas à "The Rails = Way ". Qu'est-ce que c'est?
Solution Ma question initiale a été formulée sous l'hypothèse incorrecte que debug()
retournerait les objets associés (cela fonctionne dans cakePHP car il regroupe tout dans des tableaux).
Donc, mon code d'origine devrait fonctionner. Cependant, j'avais incorrectement nommé la clé étrangère déposée dans le tableau. J'ai été confus en regardant la méthode de migration t.belongs_to
(Qui crée automatiquement le champ foreign_key correctement nommé, pas un champ nommé "appartient_à" ). J'ai donc également dû renommer cette colonne en user_id
Et maintenant cela fonctionne exactement comme décrit dans la réponse de @ Veraticus ci-dessous.
L'objet user
ne fait pas partie de l'objet project
, vous ne pourrez donc pas le visualiser sur le projet: en disant Project.includes(:user)
, vous êtes plutôt dire Rails pour charger avec impatience l'association référencée quand il trouve le projet. Cela vous évite un appel à la base de données sur la route. Par exemple, sans enthousiasme:
@project = Project.where(id: params[:id]).first # one database call, fetching the project
@project.user # another database call, fetching the user
Et avec impatience:
@project = Project.includes(:user).where(id: params[:id]).first # one database call, fetching both project and user
@project.user # no database interaction
Cela compte plus avec has_many
requêtes où les associations de chargement rapide peuvent enregistrer N + 1 requêtes de base de données.
Vous pouvez vérifier que cela fonctionne correctement en appelant @project.user
à un moment donné après le chargement enthousiaste et la vérification de vos journaux: vous devriez voir qu'il n'y a pas eu d'appel de base de données à ce stade.
Le chargement, l'optimisation des requêtes N + 1 sont vraiment un moyen efficace de charger les associations en un seul appel.
- inclut () avec where () et find ()
@project = Project.includes(:user).where(hashed_id: params[:id]).first
@project = Project.where(hashed_id: params[:id]).includes(:user).first
* Dans certains cas, cela peut être utile *
@projects = Project.find(:all, :includes => :user)
@projects = Project.find(:all, :include => [{:association1 => [:associationA, :associationB, ....]}]