2013-08-26 38 views
22

Tôi không thể tìm ra cách sử dụng phương thức .where() để truy xuất dữ liệu mô hình được liên kết. Trong ví dụ này, Dự án belongs_to Users ...Rails 4: Cách sử dụng include() với vị trí() để truy xuất các đối tượng liên quan

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 

trong App/views/dự án/invite.html.erg <%= debug(@project) %> lợi nhuận:

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

nên không phải là liên quan đến tài khoản băm/mảng được bao gồm trong này? Tôi biết tôi có thể thêm bằng tay bằng cách gọi số thứ hai find/where (@project.user = User.where({:id=>@project.belongs_to}) nhưng điều này không giống như "Đường ray". Những gì là?

Giải pháp câu hỏi ban đầu của tôi đã được xây dựng theo giả định không chính xác rằng debug() sẽ quay trở lại đối tượng liên quan (chỉ hoạt động này trong CakePHP vì nó bó tất cả mọi thứ vào mảng).

Vì vậy, mã gốc của tôi nên hoạt động. Tuy nhiên, tôi đã đặt tên không chính xác khóa ngoại được đệ trình trong bảng. Tôi đã nhầm lẫn bằng cách xem xét phương thức di chuyển t.belongs_to (tự động tạo trường nước ngoài được đặt tên chính xác, không phải trường có tên "thuộc_to"). Vì vậy, tôi cũng đã phải đổi tên cột đó thành user_id và bây giờ nó hoạt động giống như được mô tả trong câu trả lời của @ Veraticus dưới đây.

+0

biết chính xác là bạn cố gắng để hiển thị? Bạn có nghĩa là bạn muốn đầu ra gỡ lỗi hiển thị @ project.user? Hay bạn đang nói rằng 'where' và' includes' của bạn không hoạt động? Nếu bạn muốn hiển thị liên kết 'user' để gỡ rối, bạn đã thử' <% = debug (@ project.user)%> 'mà không làm thêm' user.where ... '? – lurker

+0

nếu bạn chỉ có một đối tượng dự án bao gồm không có ý nghĩa với tôi.bao gồm ý nghĩa khi một số dự án được chọn và bạn muốn tải tất cả người dùng tương ứng chỉ trong một truy vấn, đó là những gì bạn đang làm? hoặc làm thế nào bạn đang sử dụng 'bao gồm', tôi hy vọng bạn nhớ – juanpastas

+0

Các câu trả lời không còn sản xuất truy vấn đơn lẻ, nhưng cách tiếp cận này không: http://blog.arkency.com/2013/12/rails4-preloading/ – hakunin

Trả lời

37

Đối tượng user không phải là một phần của đối tượng project, vì vậy bạn sẽ không thể xem nó trên dự án: thay vào đó, bằng cách nói Project.includes(:user), bạn đang yêu cầu Rails mong muốn tải liên kết được tham chiếu khi tìm thấy dự án. Điều này giúp bạn tiết kiệm một cuộc gọi cơ sở dữ liệu xuống đường. Ví dụ, không háo hức:

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

Và háo hức:

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

này quan trọng hơn với has_many truy vấn mà các hiệp hội háo hức nạp có thể tiết kiệm N + 1 truy vấn cơ sở dữ liệu.

Bạn có thể xác minh điều này đang hoạt động phù hợp bằng cách gọi @project.user tại một số thời điểm sau khi tải và kiểm tra nhật ký mong muốn: bạn sẽ thấy rằng không có cuộc gọi cơ sở dữ liệu tại điểm đó.

+0

Huh. Vì vậy, nó * là * làm việc, tôi chỉ không biết nó bởi vì tôi (không chính xác) mong đợi 'debug' để trả về các kết hợp. Có ý nghĩa. Tuy nhiên, khi tôi '<% = debug (@ project.user)%> tôi nhận được' --- '(không có gì) .' Bất kỳ ý tưởng nào? – emersonthis

+0

Dự án của bạn có lẽ không có người dùng, là dự đoán của tôi. – Veraticus

+0

Không hoàn toàn chắc chắn những gì bạn có ý nghĩa, nhưng tôi khá chắc chắn nó. Mô hình của tôi được xác định (xem ở trên) và tôi có một hàng trong bảng người dùng của mình. Tui bỏ lỡ điều gì vậy? – emersonthis

6

Tải ứng dụng, tối ưu hóa truy vấn N + 1 thực sự là cách tải hiệu quả các liên kết trong một cuộc gọi.

- bao gồm() với nơi() và tìm()

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

* Trong một số trường hợp, nó có thể hữu ích *

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