在Rails 4.2.5 中使用嵌套资源,是否可以收集所有子元素并将它们显示在同一页面上?

Working with nested resources in Rails 4.2.5, Is it possible to gather all child elements and display them on the same page?

作为 Rails 的新手,我还没有理解参数和控制器对我整个应用程序的影响。我在整个程序中访问@variables 时遇到问题。例如,在使用父资源控制器时,当我尝试在控制器中定义@child 时,我经常会收到错误 "Couldn't find Project with 'id'=" 或“undefined method ‘children’ for nil:NilClass”。

class ProjectsController < ApplicationController
  before_action :find_project, only: [:show, :edit, :update, :destroy]
  before_action :authenticate_user!, except: [:index, :show]
  before_action :find_campaigns, only: [:index]

  def index
    if params[:search]
      @projects = Project.search(params[:search]).order("created_at DESC")
    else
      @projects = Project.all.order('created_at DESC')
    end
  end

  def new
    @project = current_user.projects.build
  end

  def create
    @project = current_user.projects.build(project_params)
    # @project = Project.new(project_params)
    if @project.save
      redirect_to @project, notice: "Successfully created new Project"
    else
      render 'new'
    end
  end

  def edit
  end

  def update
    if @project.update(project_params)
      redirect_to @project, notice: "Project was Successfully updated"
    else
      render 'edit'
    end
  end

  def show
    @random_project = Project.where.not(id: @project).order("RANDOM()").first
  end

  def destroy
    @project.destroy
    redirect_to root_path
  end

  private
  def project_params
    params.require(:project).permit(:title, :location, :goal, :investor, :description, :image, :category)

  end

  def find_project
    @project = Project.find(params[:id])
  end

  def find_campaigns
    @campaign = @project.campaigns.find(params[:id])
  end

end

以上是我的子控制器。如果我添加一个名为 find_projects 的私有方法(这是我的父对象),有没有办法访问所有项目的所有子项并将它们显示在一页上?

您将遍历每个项目并访问其 children。首先删除您的 find_campaigns 方法和 before_action :find_campaigns,因为它们不需要。

打开app/views/projects/index.html.erb

<% if @projects.any? %>
  <ul class="projects">
    <% @projects.each do |p| %>
    <li>
      <h3><%= p.name %></h3>
      <% if p.campaigns.any? %>
      <ul class="campaigns">
        <% @p.campaigns.each do |c| %>
        <li><%= c.name %><li>
        <% end %>
      </ul>
      <% end %>
    </li>
    <% end %>
  </ul>
<% end %>

然而,在执行此操作时需要小心,因为您会导致所谓的 N+1 查询,其中 @projects.each 的每次迭代都会执行单独的 SQL 查询以获取children 这真的很慢。

我们可以通过使用 includes 来避免这种情况,以便一次性加载广告系列:

def find_project
  @project = Project.includes(:campaigns).find(params[:id])
end

您可能想看看 the Rails Guides,因为它有一些非常好的技巧,可以使用部分来清理上面的循环。