Подтвердить что ты не робот

Rails 4: Как использовать include() с where() для извлечения связанных объектов

Я не могу понять, как пользователю использовать метод .where() для получения связанных данных модели. В этом примере Projects принадлежит_to Users...

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

В приложении /views/projects/invite.html.erg <%= debug( @project ) %> возвращается:

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

Не следует ли включить в него связанный хэш/массив пользователя? Я знаю, что могу добавить его вручную, вызвав второй find/where (@project.user = User.where( {:id=>@project.belongs_to}), но это не похоже на "The Rails Way". Что такое?

Решение Мой первоначальный вопрос был сформулирован под неправильным предположением о том, что debug() будет возвращать связанные объекты (это работает в cakePHP, потому что он объединяет все в массивы).

Итак, мой исходный код должен работать. Однако я неправильно назвал внешний ключ, указанный в таблице. Я запутался, посмотрев на метод миграции t.belongs_to (который автоматически создает правильно названное поле foreign_key, а не поле с именем "принадлежит" ). Поэтому мне также пришлось переименовать этот столбец в user_id, и теперь он работает так, как описано в ответе @Veraticus ниже.

4b9b3361

Ответ 1

Объект user не является частью объекта project, поэтому вы не сможете его просмотреть в проекте: скорее, говоря Project.includes(:user), вы сообщаете Rails, чтобы он загружал если он находит проект. Это экономит вам вызов базы данных по дороге. Например, не нетерпеливо:

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

И с нетерпением:

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

Это больше связано с запросами has_many, где ассоциации с поддержкой загрузки могут сохранять запросы базы данных N + 1.

Вы можете убедиться, что это работает надлежащим образом, вызвав @project.user в какой-то момент после интенсивной загрузки и проверки ваших журналов: вы должны увидеть, что в этот момент не было вызова базы данных.

Ответ 2

Желательная загрузка, оптимизация запросов N + 1 - действительно эффективный способ загрузки ассоциаций в один вызов.

- включает(), где() и find()

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

* В некоторых случаях может быть полезно *

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