0

私のアプリケーションには、複雑なデータベース構造があります。呼び出しに対する JSON 応答を生成するには、多数の結合テーブルからデータを取得する必要があります。

必要なすべてのデータを取得する SQL クエリを作成しました (rails を使用includes)。しかし、ビューに結果が表示されたので、実際にレンダリングする正しい方法がわかりません。

の実際のコードではなく、簡単な例:タスクを含むサブプロジェクトを含むあり、クエリがそれらすべてのネストされた構造をいくつかのロジックに従ってフィルター処理して返すとします。

class Project < ActiveRecord::Base
  ...
  def with_sub_projects_visible_by(user)
    includes(...complex join with sub projects and tasks...)
    .where(...complex condition...)
  end
end

コントローラーには、次のようなものがあります。

  def show
    @project_with_full_details = Project.find(params[:id]).with_sub_projects_visible_by(current_user)
  end

@project_with_full_detailsデータベースを再度呼び出さずにすべてのデータを含むページをレンダリングする単純なビュー コードを作成する方法はありますか? 私が試したことから、単に電話をかけるだけではうまくいき@project_with_full_details.sub_projectsません。データベースを呼び出して、クエリ結果に含まれるはずのフィルタリングされたものではなく、関連する sub_projects の完全なリストを取得します。

(JSON をレンダリングしているので、ビューに RABL を使用していますが、それほど重要ではありません。ERB の例はまったく問題ありません)

4

1 に答える 1

1

ActiveRecord は関連付け用のプリローダーを提供します。これにより、Rails はデータベースからオブジェクトを 1 回だけロードします (ページがロードされる前にも発生します)。

あなたの例では、おそらく次のようになります。

@project = Project.find(params[:id])
ActiveRecord::Associations::Preloader.new(
  @project, [ :subprojects, subprojects: :tasks]
)

これにより、少なくとも SQL を 1 回だけ実行するという望ましい効果が得られます。

モデルが次のような場合:

class Project
  has_many :users
  has_many :sub_projects
  has_many :tasks, through: :sub_projects
  ...
end

次に、おそらく のようなメソッドを定義できますsubprojects_for(user)。次に、次の行に沿って何かを実行できるはずです。

# controller
@project = Project.find(params[:id])
@subprojects = @project.subprojects_for(current_user)

# haml
.project
  = @project.title
  - @project.subprojects_for(current_user).each do |subproject|
    = Something for subprojects...
    - subproject.tasks.each do |task|
      = You get the idea

ただし、本当の魔法はプリローダーで発生するはずでした。サーバー ログを調べて、SQL が複数回実行されていることを確認したと思いますか?

于 2012-07-02T18:42:18.293 に答える