首页 > 解决方案 > 在 Rails 中加载嵌套资源的正确方法

问题描述

在我们的 Rails 应用程序中,我们有一些相当深的嵌套路由。这引起了一些混乱,即如何最好地在控制器中加载资源。

例如,我们可能有这样的设置:

/clients/:client_id/products/:product_id/builds/:build_id/downloads/:id

在我们的下载控制器中,我们可能有:

class DownloadsController < ApplicationController

    before_action :assign_instance_variables

    def index
        @downloads = Download.where(build_id: params[:build_id])
    end

    def show
        @download = Download.find(params[:id])
    end

    private

        def assign_instance_variables
            @client = Client.find(params[:client_id])
            @product = Product.find(params[:product_id])
            @build = Build.find(params[:build_id])
        end
end

但是我们注意到这实际上允许您将下载的 ID 从另一个版本更改为一个,即使它没有关联,它仍然可以正常加载它,因为我们不查看关联......

所以我们对其进行了重构:

class DownloadsController < ApplicationController

    before_action :assign_instance_variables

    def index
        @downloads = @build.downloads
    end

    def show
        @download = @build.downloads.find(params[:id])
    end

    private

        def assign_instance_variables
            @client = Client.find(params[:client_id])
            @product = @client.products.find(params[:product_id])
            @build = @product.builds.find(params[:build_id])
        end
end

这意味着整个嵌套中的所有 ID 都会根据父对象进行检查,如果有任何失败,它将引发 ActiveRecord::NotFound。

我们也想过这样做:

@download = Download.find(params[:id]
@build = @download.build
@product = @build.product
@client = @product.client

所以我们只进行一次查找,然后沿着链备份,但这会引入一个问题,即除了下载 ID 之外,没有任何 ID 被使用,这意味着您可以输入任何内容,并且 URL 仍然被认为是有效的......

处理获取所有嵌套资源的正确方法是什么?

标签: ruby-on-rails

解决方案


推荐阅读