我的 Rails 视图和控制器充斥着redirect_to
、link_to
和form_for
方法调用。有时link_to
和redirect_to
在它们链接的路径中是显式的(例如link_to 'New Person', new_person_path
),但很多时候路径是隐式的(例如link_to 'Show', person
)。
我在模型中添加了一些单表继承(STI)(比如Employee < Person
),所有这些方法都因子类的实例而中断(比如Employee
);当 rails 执行时link_to @person
,它会出错undefined method employee_path' for #<#<Class:0x000001022bcd40>:0x0000010226d038>
。Rails 正在寻找由对象的类名定义的路由,即employee。这些员工路线没有定义,也没有员工控制器,因此也没有定义操作。
之前有人问过这个问题:
- 在StackOverflow,答案是在整个代码库中编辑 link_to 等的每个实例,并明确说明路径
- 再次在StackOverflow上,有两个人建议使用
routes.rb
将子类资源映射到父类(map.resources :employees, :controller => 'people'
)。同一个 SO 问题中的最佳答案建议使用类型转换代码库中的每个实例对象.becomes
- StackOverflow上的另一个问题,最佳答案是 Do Repeat Yourself 阵营,并建议为每个子类创建重复的脚手架。
- 在SO再次出现同样的问题,其中最佳答案似乎是错误的(Rails magic Just Works!)
- 在网络的其他地方,我发现了这篇博文,F2Andy 建议在代码中各处的路径中进行编辑。
- 在 Logical Reality Design的博客文章Single Table Inheritance and RESTful Routes中,建议将子类的资源映射到超类控制器,如上面的 SO 答案 2 中所示。
- Alex Reisner 在 Rails 中有一篇文章Single Table Inheritance,其中他主张反对将子类的资源映射到父类
routes.rb
,因为这只能捕获来自link_to
and的路由中断redirect_to
,而不是来自form_for
. 所以他建议改为向父类添加一个方法,让子类对他们的类撒谎。听起来不错,但他的方法给了我错误undefined local variable or method `child' for #
。
所以看起来最优雅和最一致的答案(但它不是那么优雅,也不是那么一致),就是将资源添加到你的routes.rb
. 除非这不适用于form_for
. 我需要一些澄清!为了提炼上面的选择,我的选择是
- 将子类的资源映射到超类的控制器中
routes.rb
(并希望我不需要在任何子类上调用 form_for) - 覆盖 rails 内部方法以使类相互欺骗
- 编辑代码中隐式或显式调用对象操作路径的每个实例,更改路径或对对象进行类型转换。
有了所有这些相互矛盾的答案,我需要一个裁决。在我看来,没有好的答案。这是rails设计的失败吗?如果是这样,这是一个可以修复的错误吗?或者如果不是,那么我希望有人可以让我明白这一点,让我了解每个选项的优缺点(或解释为什么这不是一个选项),哪个是正确答案,以及为什么。或者有没有我在网上找不到的正确答案?