2013-08-26 11 views
22

Non riesco a capire come utilizzare il metodo .where() per recuperare i dati del modello associati. In questo esempio, Progetti belongs_to utenti ...Rails 4: Come usare includes() con where() per recuperare gli oggetti associati

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 

In App/views/progetti/invite.html.erg <%= debug(@project) %> rendimenti:

--- !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' 

Nel caso non l'utente hash/array associati essere inclusi in questo? So che potrei aggiungerlo manualmente chiamando un secondo find/where (@project.user = User.where({:id=>@project.belongs_to}) ma questo non sembra "The Rails Way". Cosa è?

Soluzione mia domanda iniziale è stata formulata in base al presupposto errato che debug() sarebbero tornati gli oggetti associati (questo funziona in cakePHP perché impacchetta tutto in array).

Quindi il mio codice originale dovrebbe funzionare. Tuttavia, avevo erroneamente chiamato la chiave esterna archiviata nella tabella. Mi sono confuso osservando il metodo di migrazione t.belongs_to (che crea automaticamente il campo foreign_key con nome corretto, non un campo denominato "appartiene a"). Così ho anche dovuto rinominare quella colonna su user_id e ora funziona esattamente come descritto nella risposta di @ Veraticus qui sotto.

+0

Che cosa stai cercando mostrare? Intendi che vuoi che l'output di debug mostri @ project.user? O stai dicendo che i tuoi 'where' e' includes' non stanno funzionando? Se vuoi mostrare l'associazione 'utente' per il debug, hai provato' <% = debug (@ project.user)%> 'senza eseguire' user.where ... '? – lurker

+0

se un solo oggetto di progetto include non ha senso per me.include senso quando diversi progetti sono selezionati e vuoi caricare tutti i rispettivi utenti in una sola query, è quello che stavi facendo? o come stai usando 'include', spero che ti ricordi – juanpastas

+0

Le risposte non producono più una singola query, ma questo approccio funziona: http://blog.arkency.com/2013/12/rails4-preloading/ – hakunin

risposta

37

L'oggetto user non è parte dell'oggetto project, quindi non sarà in grado di visualizzarlo sul progetto: piuttosto, dicendo Project.includes(:user), stai dicendo Rails per ansioso-caricare l'associazione si fa riferimento quando trova il progetto. Questo ti risparmia una chiamata al database in fondo alla strada. Ad esempio, non con entusiasmo:

@project = Project.where(id: params[:id]).first # one database call, fetching the project 
@project.user # another database call, fetching the user 

e con entusiasmo:

@project = Project.includes(:user).where(id: params[:id]).first # one database call, fetching both project and user 
@project.user # no database interaction 

Questo è più importante con has_many query in cui le associazioni ansioso-carico possono salvare N + 1 query di database.

È possibile verificare questo sta funzionando in modo appropriato chiamando @project.user ad un certo punto, dopo il carico e ansioso, verifica la log: si dovrebbe vedere che non vi era alcuna chiamata di database in quel punto.

+0

Huh. Quindi * è * funzionante, semplicemente non lo so perché sto aspettando (erroneamente) 'debug' per restituire le associazioni. Ha senso. Tuttavia, quando I '<% = debug (@ project.user)%> ottengo' --- '(nothing) .' Qualche idea? – emersonthis

+0

Probabilmente il tuo progetto non ha utenti, è la mia ipotesi. – Veraticus

+0

Non sono abbastanza sicuro di cosa intendi, ma sono abbastanza sicuro che lo faccia. I miei modelli sono definiti (vedi sopra) e ho una riga nella mia tabella utenti. Mi sto perdendo qualcosa? – emersonthis

6

Eager caricamento, ottimizzazione della query N + 1 è davvero un modo efficiente di caricare associazioni in una singola chiamata.

- include() con cui() e trovare()

@project = Project.includes(:user).where(hashed_id: params[:id]).first 
@project = Project.where(hashed_id: params[:id]).includes(:user).first 

* In alcuni casi, può essere utile *

@projects = Project.find(:all, :includes => :user) 
@projects = Project.find(:all, :include => [{:association1 => [:associationA, :associationB, ....]}] 
Problemi correlati