2013-08-26 12 views
22

Nie mogę dowiedzieć się, jak użyć metody .where(), aby pobrać powiązane dane modelu. W tym przykładzie, Projekty Użytkowników belongs_to ...Szyny 4: Sposób korzystania zawiera() z where() do pobierania powiązanych obiektów

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 

w app/views/Projekty/invite.html.erg <%= debug(@project) %> Powroty:

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

Gdyby nie wiąże się Użytkownik hash/array być włączone w tym? Wiem, że mogłem ręcznie dodać go, dzwoniąc po drugie find/where (@project.user = User.where({:id=>@project.belongs_to}), ale to nie brzmi jak "The Rails Way". Co jest?

Rozwiązanie Moje pierwsze pytanie zostało sformułowane na podstawie błędnego założenia, że ​​debug() wróci powiązanych obiektów (to działa w CakePHP ponieważ wiązki wszystko pod tablicami).

Więc mój oryginalny kod powinien działać. Jednak nieprawidłowo nazwałem klucz obcy złożony w tabeli. Byłem zdezorientowany, patrząc na metodę migracji t.belongs_to (która automatycznie tworzy poprawnie nazwane pole klucza obcego, , a nie w polu o nazwie "belongs_to"). Tak więc musiałem zmienić nazwę tej kolumny na user_id i teraz działa ona tak, jak opisano w odpowiedzi @ Veraticus poniżej.

+0

Co dokładnie próbujesz pokazywać? Czy masz na myśli, że chcesz wyświetlać dane wyjściowe debugowania pokazujące plik @ project.user? Czy mówisz, że twoje "gdzie" i "zawiera" nie działają? Jeśli chcesz pokazać powiązanie 'user' dla debugowania, czy wypróbowałeś' <% = debug (@ project.user)%> 'bez wykonywania dodatkowego' user.where ... '? – lurker

+0

jeśli masz tylko jeden obiekt projektu obejmuje nie ma dla mnie sensu.obejmuje sens, gdy wybranych jest kilka projektów i chcesz załadować wszystkich odpowiednich użytkowników w jednym zapytaniu, czy to właśnie robiłeś? lub w jaki sposób używasz 'zawiera', mam nadzieję, że pamiętasz – juanpastas

+0

Odpowiedzi nie są już tworzenie pojedynczego zapytania, ale to podejście ma: http://blog.arkency.com/2013/12/rails4-preloading/ – hakunin

Odpowiedz

37

Przedmiotem user nie jest częścią obiektu project, więc nie będą mogli go zobaczyć na projekcie: raczej, mówiąc Project.includes(:user), mówisz szyn chętny załadowanie odwołuje stowarzyszenie gdy stwierdzi projekt. To oszczędza połączenie z bazą danych w dół drogi. Na przykład, nie z niecierpliwością:

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

i chętnie:

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

to ważniejsze z has_many zapytaniami gdzie stowarzyszenia chętny-loading może uratować N + 1 zapytań do bazy danych.

Możesz sprawdzić, czy działa prawidłowo, dzwoniąc pod numer @project.user po pewnym obciążeniu i sprawdzeniu logów: powinieneś zauważyć, że w tym momencie nie było połączenia z bazą danych.

+0

Huh. Tak więc * działa *, po prostu tego nie wiem, ponieważ (niepoprawnie) oczekuję, że 'debug' zwróci skojarzenia. Ma sens. Jednakże, gdy '<% = debug (@ project.user)%> otrzymuję' --- '(nic). Jakieś pomysły? – emersonthis

+0

Twój projekt prawdopodobnie nie ma użytkownika, to moje przypuszczenie. – Veraticus

+0

Nie jestem pewien, co masz na myśli, ale jestem prawie pewien, że tak. Moje modele są zdefiniowane (patrz wyżej) i mam jeden wiersz w tabeli użytkowników. Czy czegoś brakuje? – emersonthis

6

Chętne ładowanie, optymalizacja zapytań N + 1 to naprawdę skuteczny sposób na ładowanie skojarzeń w jednym wywołaniu.

- obejmuje() z gdzie() i odnaleźć()

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

* W niektórych przypadkach może to być przydatne *

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