web-dev-qa-db-ja.com

Rails 4:include()とwhere()を使用して関連オブジェクトを取得する方法

.where()メソッドを使用して、関連するモデルデータを取得する方法がわかりません。この例では、Projects belongs_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
end
_

App/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'
_

関連するユーザーハッシュ/配列をこれに含めるべきではありませんか? 2番目のfind/where(_@project.user = User.where( {:id=>@project.belongs_to}_)を呼び出して手動で追加できることは知っていますが、これは「The Rails方法」とは何ですか?

Solution私の最初の質問は、debug()が関連オブジェクトを返すという誤った仮定の下で定式化されました(これは、すべてを配列にバンドルするため、cakePHPで機能します)。

だから私の元のコードshouldは動作します。ただし、テーブルにファイルされた外部キーの名前は間違っていました。移行方法_t.belongs_to_(正しい名前のforeign_keyフィールドを自動的に作成し、not「belongs_to」というフィールドを見て混乱しました) 。そのため、その列の名前を_user_id_に変更する必要もありましたが、現在は以下の@Veraticusの回答で説明されているとおりに機能します。

22
emersonthis

userオブジェクトはprojectオブジェクトの一部ではないため、プロジェクトで表示することはできません。むしろ、Project.includes(:user)と言うことで、 telling 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を呼び出してログを確認します。その時点でデータベース呼び出しがなかったことを確認する必要があります。

37
Veraticus

積極的な読み込み、N + 1クエリの最適化は、1回の呼び出しで関連付けを読み込む効率的な方法です。

-where()およびfind()を含むinclude()

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