处理 rails 中 STI 子类的路由的最佳实践 [英] Best practices to handle routes for STI subclasses in rails

查看:27
本文介绍了处理 rails 中 STI 子类的路由的最佳实践的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的 Rails 视图和控制器充满了 redirect_tolink_toform_for 方法调用.有时 link_toredirect_to 在它们链接的路径中是明确的(例如 link_to 'New Person', new_person_path),但很多时候路径是隐式的(例如 link_to 'Show', person).

My Rails views and controllers are littered with redirect_to, link_to, and form_for method calls. Sometimes link_to and redirect_to are explicit in the paths they're linking (e.g. link_to 'New Person', new_person_path), but many times the paths are implicit (e.g. link_to 'Show', person).

我将一些单表继承 (STI) 添加到我的模型中(比如 Employee ),并且所有这些方法都因子类的实例而中断(比如 Employee)代码>);当 rails 执行 link_to @person 时,它会出现 undefined method employee_path' for #<#<Class:0x0000001022bcd40>:0x0000010226d038> 的错误.Rails 正在寻找由对象的类名定义的路由,即员工.这些员工路线未定义,也没有员工控制器,因此也未定义操作.

I add some single table inheritance (STI) to my model (say Employee < Person), and all of these methods break for an instance of the subclass (say Employee); when rails executes link_to @person, it errors with undefined method employee_path' for #<#<Class:0x000001022bcd40>:0x0000010226d038>. Rails is looking for a route defined by the class name of the object, which is employee. These employee routes are not defined, and there is no employee controller so the actions aren't defined either.

以前有人问过这个问题:

This question has been asked before:

  1. StackOverflow,答案是编辑每个整个代码库中的 link_to 等实例,并明确说明路径<​​/li>
  2. 再次在 StackOverflow 上,两个人们建议使用 routes.rb 将子类资源映射到父类(map.resources :employees, :controller => 'people').同一 SO 问题中的最佳答案建议使用 .becomes
  3. 对代码库中的每个实例对象进行类型转换
  4. StackOverflow 上的另一个,最佳答案是 Do Repeat Yourself 阵营中的方式,并建议为每个子类创建重复的脚手架.
  5. 这是同样的问题,在 SO 上再次出现,上面的答案似乎是错误的(Rails 魔法就行!)
  6. 在网络的其他地方,我发现了这篇博文F2Andy 建议在代码中随处可见的路径中进行编辑.
  7. 在博客文章 单表继承和 RESTful路线 在逻辑现实设计中,建议将子类的资源映射到超类控制器,如上面的 SO 答案 2 所示.
  8. Alex Reisner 发表了一篇Rails 中的单表继承,其中他主张不要将子类的资源映射到 routes.rb 中的父类,因为这只会捕获来自 link_toredirect_to<的路由中断/code>,但不是来自 form_for.因此,他建议改为向父类添加一个方法,以使子类对其类撒谎.听起来不错,但是他的方法给了我错误undefined local variable or method `child' for #.
  1. At StackOverflow, the answer is to edit every instance of link_to etc in your entire codebase, and state the path explicitly
  2. On StackOverflow again, two people suggest using routes.rb to map the subclass resources to the parent class (map.resources :employees, :controller => 'people'). The top answer in that same SO question suggests type-casting every instance object in the codebase using .becomes
  3. Yet another one at StackOverflow, the top answer is way in the Do Repeat Yourself camp, and suggests creating duplicate scaffolding for every subclass.
  4. Here's the same question again at SO, where the top answer seems to just be wrong (Rails magic Just Works!)
  5. Elsewhere on the web, I found this blog post where F2Andy recommends editing in the path everywhere in the code.
  6. On the blog post Single Table Inheritance and RESTful Routes at Logical Reality Design, it is recommended to map the resources for the subclass to the superclass controller, as in SO answer number 2 above.
  7. Alex Reisner has a post Single Table Inheritance in Rails, in which he advocates against mapping the resources of the child classes to the parent class in routes.rb, since that only catches routing breakages from link_to and redirect_to, but not from form_for. So he recommends instead adding a method to the parent class to get the subclasses to lie about their class. Sounds good, but his method gave me the error undefined local variable or method `child' for #.

因此,看起来最优雅、最有共识的答案(但并不是所有那个优雅,也不是那个很多共识),就是将资源添加到您的routes.rb.除非这不适用于 form_for.我需要一些清晰度!为了提炼上面的选择,我的选择是

So the answer that seems most elegant and has the most consensus (but it's not all that elegant, nor that much consensus), is the add the resources to your routes.rb. Except this doesn't work for form_for. I need some clarity! To distill the choices above, my options are

  1. routes.rb中将子类的资源映射到超类的控制器(希望我不需要在任何子类上调用form_for)
  2. 重写 rails 内部方法,使类相互欺骗
  3. 编辑代码中隐式或显式调用对象操作路径的每个实例,更改路径或类型转换对象.
  1. map the resources of the subclass to the controller of the superclass in routes.rb (and hope I don't need to call form_for on any subclasses)
  2. Override rails internal methods to make the classes lie to each other
  3. Edit every instance in the code where the path to an object's action is invoked implicitly or explicitly, either changing the path or type-casting the object.

有了所有这些相互矛盾的答案,我需要一个裁决.在我看来,没有好的答案.这是导轨设计的失败吗?如果是这样,它是一个可以修复的错误吗?或者,如果不是,那么我希望有人可以让我直截了当,引导我了解每个选项的优缺点(或解释为什么这不是一个选项),哪个是正确的答案,以及为什么.或者有没有我在网上找不到的正确答案?

With all these conflicting answers, I need a ruling. It seems to me like there is no good answer. Is this a failing in rails' design? If so, is it a bug that may get fixed? Or if not, then I'm hoping someone can set me straight on this, walk me through the pros and cons of each option (or explain why that's not an option), and which one is the right answer, and why. Or is there a right answer that I'm not finding on the web?

推荐答案

这是我能想出的最简单的解决方案,而且副作用最小.

This is the simplest solution I was able to come up with with minimal side effect.

class Person < Contact
  def self.model_name
    Contact.model_name
  end
end

现在 url_for @person 将按预期映射到 contact_path.

Now url_for @person will map to contact_path as expected.

工作原理:URL 助手依赖 YourModel.model_name 来反映模型并生成(在许多方面)单数/复数路由键.这里Person 基本上是在说我就像Contact 伙计,问他.

How it works: URL helpers rely on YourModel.model_name to reflect upon the model and generate (amongst many things) singular/plural route keys. Here Person is basically saying I'm just like Contact dude, ask him.

这篇关于处理 rails 中 STI 子类的路由的最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆