Rails 3 - 嵌套资源和多态路径:可以到两个级别,但在三个级别中断

Posted

技术标签:

【中文标题】Rails 3 - 嵌套资源和多态路径:可以到两个级别,但在三个级别中断【英文标题】:Rails 3 - Nested resources and polymorphic paths: OK to two levels, but break at three 【发布时间】:2011-08-20 13:46:07 【问题描述】:

我正在尝试创建一个简单的家庭团聚网站,其中包含:“帖子”、“家庭”、“孩子”和“图片”。理想情况下,我希望以这种方式构建路线/关系:

  resources :posts do
    resources :pictures
  end

  resources :fams do
     resources :pictures
     resources :kids do
       resources :pictures
     end
  end

在模型中,我在famskids 之间设置了必要的“belongs_to”和“has_many”关系。 Famskidsposts都用"has_many :pictures, :as => :imageable定义,而图片定义为:belongs_to :imageable, :polymorphic => true

当尝试在pictures 视图中执行link_to "Edit"link_to "Destroy" 时,我遇到了各种_path 问题。 polymoric_path 在两个级别上都可以正常工作,即posts-picturesfams-pictures,但它无法处理fams-kids-pictures 的三个级别的情况。我猜它不是为处理picture 对象上方的两个级别的“imageable”对象而设计的。另一个问题是,在一个实例中,pictures 控制器必须处理“一层”资源嵌套情况,而在另一种情况下,它必须处理“两层”情况。不知道如何处理。

根据 Ruby Guides 的指示,我尝试过的一件事是不要将资源嵌套深度超过一层。我的结构是这样的:

  resources :posts do
    resources :pictures
  end

  resources :fams do
     resources :pictures
     resources :kids
  end

  resources :kids do
     resources :pictures
  end

这导致了另一组路径问题,因为不再保留亲子关系。我也无法让 polymorphic_path 在所有不同的picture 视图中正常运行。

所以这是我的主要问题:有谁知道 Rails 3 示例/教程,其中嵌套资源、属于/has_many 和多态关系都放在一起,尤其是在它不仅仅是简单的两级的地方大多数例子显示的关系? (我对 Rails 还很陌生,鉴于我缺乏 Rails 历史经验,我在这些领域发现的 Rails 2 示例令人困惑。)

或者谁能告诉我如何为我的picture 视图构建link_to EDITlink_to DELETE 语句,以及我的createupdatedestroy 方法的redirect-to 语句在我的pictures 控制器中?

谢谢!

【问题讨论】:

【参考方案1】:

您将嵌套限制为 2 级的代码示例非常接近答案。为避免 fams->kids 和 kids 的路线重复,您可以使用带有空白数组的 :only 选项,以便 1st-level kids 不会生成路线,除非在 kids->pictures 的上下文中,如下所示:

resources :posts do
  resources :pictures
end

resources :fams do
  resources :pictures
  resources :kids
end

resources :kids, only: [] do # this will not generate kids routes
   resources :pictures
end

对于上述代码,您可以使用以下内容来构造您的多态编辑 url:

polymorphic_url([fam, picture], action: :edit) # using Ruby 1.9 hash syntax
polymorphic_url([kid, picture], action: :edit)

【讨论】:

【参考方案2】:

这个问题已经有一段时间了。我现在可以使用它,但它并不漂亮:S

来自嵌套的怪物,例如:

http://localhost:3000/destinations/3/accommodations/3/accommodation_facilities/52

您的 params 对象最终看起来像这样:

action: show
id: "52"
destination_id: "3"
accommodation_id: "3"
controller: accommodation_facilities

其中“id”表示当前模型 id(链上的最后一个),其他的有 model_name_id

要在此页面上正确呈现另一个嵌套链接,您需要传入构成完整路径的对象数组,例如链接到您必须执行的虚构 FacilityType 对象:

 <%= link_to "New", new_polymorphic_path([@destination, @accommodation, @accommodation_facility, :accommodation_facility_type]) %>

为了从 params 对象生成这个数组,我在 application_helper.rb 中使用了这段代码

def find_parent_models(current_model = nil)
    parents = Array.new

    params.each do |name, value|
      if name =~ /(.+)_id$/
        parents.push $1.classify.constantize.find(value)
      end
    end

    parents.push current_model

    parents
end

那么要自动建立相同的链接,你可以愉快地做:

 <%= link_to "New", new_polymorphic_path(find_parent_models(@accommodation_facility).push(:accommodation_facility_type)) %>

非常欢迎任何关于使这个解决方案不那么粗略的建议:]

【讨论】:

如果某些用户键入的地址以:..facilities/52?user_id=1&amp;pathname_id=/etc/passwd&amp;application_controller_id=1&amp;xyzzy_id=1&amp;file_utils_id=1... 等结尾怎么办?我假设你有一个很好的 500.html 设计? ;-)) 这是一张小猫的照片。有趣的一点,但是rails没有这个问题吗?如果我尝试: localhost:3000/destinations/1/?destination_id=1 它已经吓坏了 拥有一个名为 'xyzzy_id' 的参数 Rails 不会自行将其常量化。如果攻击者能够找到响应 'find' 方法的类,他可能会做一些非常讨厌的事情。 好点。尽管攻击者只能将不需要的对象放入范围以构建 polymorphic_path,这可能是无效的。您有替代解决方案吗? 我认为可接受父母的白名单会让每个人都开心。【参考方案3】:

我不能说多态关联问题(可能需要有关实际错误的更多信息),但通过将嵌套资源定义为仅一层深度,您确实朝着正确的方向前进。这是 Jamis Buck 的 popular article,它已成为参考,您可能应该查看一下。

【讨论】:

是的,我已经读过那篇文章很多次了。我觉得很肤浅。为简单起见,但没有解决如何通过多个级别维护关系。用它需要的动态路径添加多态性,你有一个非常复杂的问题,我所见过的任何东西都没有很好地解决这个问题。我已经准备好转储多态性并开始通过为我的每个主要数据模型构建不同的图片控制器来重复自己。 DRY 就这么多。

以上是关于Rails 3 - 嵌套资源和多态路径:可以到两个级别,但在三个级别中断的主要内容,如果未能解决你的问题,请参考以下文章

Rails 命名空间与嵌套资源

对嵌套注释使用 Rails 多态性

如何避免Rails 5嵌套资源命名空间路由中的双下划线

Rails 不区分嵌套在相同命名空间中的两个资源

在 Rails 中嵌套资源时的不同视图

ruby 中:Rails:嵌套路由,多态关联和控制器(https://medium.com/@loickartono/rails-nested-routes-polymorphic-as