web-dev-qa-db-fra.com

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.

22
emersonthis

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.

37
Veraticus

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, ....]}]
6
przbadu