在Rails中处理STI子类路由的最佳实践

15 浏览
0 Comments

在Rails中处理STI子类路由的最佳实践

我的Rails视图和控制器中散布着redirect_tolink_toform_for方法的调用。有时,link_toredirect_to在它们链接的路径中是明确的(例如link_to \'New Person\', new_person_path),但很多时候路径是隐含的(例如link_to \'Show\', person)。\n我在我的模型中添加了一些单表继承(STI)(比如Employee < Person),所有这些方法对于子类的实例(比如Employee)都会出错;当Rails执行link_to @person时,会报错undefined method employee_path\' for #<#:0x0000010226d038>。Rails正在寻找由对象的类名定义的路由,即employee。这些employee路由没有被定义,也没有employee控制器,因此这些动作也没有被定义。\n这个问题以前已经被提出过:\n

    \n

  1. StackOverflow上,答案是在整个代码库中编辑每个link_to等的实例,并明确指定路径
  2. \n

  3. StackOverflow上,有两个人建议使用routes.rb将子类资源映射到父类(map.resources :employees, :controller => \'people\')。同样在那个SO问题中,排名第一的答案建议使用.becomes来对代码库中的每个实例对象进行类型转换。
  4. \n

  5. StackOverflow上,排名第一的答案属于重复自己的阵营,并建议为每个子类创建重复的脚手架。
  6. \n

  7. 这里是在SO上再次提出的同一个问题,排名第一的答案似乎是错误的(Rails的魔力工作正常!)
  8. \n

  9. 在网络的其他地方,我找到了这篇博文,F2Andy建议在代码中的每个地方编辑路径。
  10. \n

  11. 在Logical Reality Design的博文Single Table Inheritance and RESTful Routes中,建议将子类的资源映射到父类控制器,就像上面的SO答案2一样。
  12. \n

  13. Alex Reisner在他的博文Single Table Inheritance in Rails中,反对将子类的资源映射到父类控制器的做法,因为那只能解决link_toredirect_to导致的路由问题,而不能解决form_for导致的问题。因此,他建议在父类中添加一个方法,使子类对其类别撒谎。听起来不错,但他的方法给我报错undefined local variable or method `child\' for #
  14. \n

\n所以看起来最优雅且最有共识的答案(但并不是那么优雅,也没有那么多共识),是在routes.rb中添加资源。但是这对于form_for来说是行不通的。我需要一些明确的答案!为了梳理上述选择,我的选择是:\n

    \n

  1. routes.rb中将子类的资源映射到父类控制器(并希望不需要在任何子类上调用form_for)
  2. \n

  3. 覆盖Rails内部方法,使各个类相互撒谎
  4. \n

  5. 编辑代码中的每个实例,无论是显式还是隐式地调用对象的操作路径,都要更改路径或对对象进行类型转换。
  6. \n

\n由于这些互相冲突的答案,我需要一个决定。我觉得Rails的设计有缺陷吗?如果是这样,这可能是一个会被修复的错误吗?如果不是,那么我希望有人能给我指点,为每个选项的利弊做出解释(或者解释为什么这不是一个选项),并告诉我哪个是正确答案,为什么。或者是否有一个正确答案我在网络上没有找到的?

0
0 Comments

最佳实践:处理Rails中STI子类的路由

在Rails中,处理STI(Single Table Inheritance,单表继承)子类的路由时,可能会遇到一些问题。为了解决这些问题,可以参考以下最佳实践。

问题的出现原因:

在处理STI子类的路由时,可能会遇到无法使用"form_for"的问题。这是因为在Rails中,默认情况下,使用"form_for"生成表单时,会根据对象的类名生成对应的路由。但是对于STI子类,由于其类名不同于父类,因此无法正确生成对应的路由。

解决方法:

为了解决这个问题,可以使用ActiveRecord::Base#becomes方法将子类对象转换为父类对象。这样就可以使用父类的路由来处理子类的表单提交。

具体做法是在表单中显式设置url参数,将子类对象转换为父类对象,然后使用父类的路由来处理表单的提交。下面是示例代码:

<%= form_for @child.becomes(Parent) do |f| %>
  # 表单内容
<% end %>

这样,就可以正确地生成和处理STI子类的路由了。

参考链接:https://stackoverflow.com/a/605172/445908

0
0 Comments

在使用STI后,form_for方法在提交时会发往错误的子类URL,出现了NoMethodError (undefined method `building_url' for错误。为了解决这个问题,我添加了额外的子类路由,并将它们指向相同的控制器:

resources :structures
resources :buildings, :controller => 'structures'
resources :bridges, :controller => 'structures'

此外,<% form_for(, :as => :structure) do |f| %>,在这种情况下,structure实际上是一个building(子类)。

使用form_for提交后,这种方式对我有效。

这种方法能够解决问题,但在我们的路由中增加了很多不必要的路径。难道没有一种不那么侵入性的方法来解决这个问题吗?

你可以在routes.rb文件中通过编程的方式设置路由,因此你可以进行一些元编程来设置子类路由。然而,在类没有被缓存的环境中(例如开发环境),您需要预先加载这些类。所以不管哪种方式,您都需要在某个地方指定子类。可以参考gist.github.com/1713398中的示例。

在我的情况下,将对象名称(路径)暴露给用户是不可取的(对用户来说会很困惑)。

0
0 Comments

在Rails中处理STI子类的路由的最佳实践

问题的出现原因:在Rails中,当使用单一表继承(STI)模式时,路由助手(URL helpers)可能会出现问题。这是因为路由助手依赖于模型名称来生成路由键,而STI子类的模型名称可能会导致错误的路由生成。

解决方法:有几种解决方法被提出,以下是其中一种最佳实践的解决方法:

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

这段代码中,`Person`类重写了`model_name`方法,将其指向父类`Contact`的`model_name`方法。这样一来,调用`url_for`方法时,就会按照预期将路由映射到`contact_path`。

这种解决方法的原理是,路由助手依赖于`YourModel.model_name`来反映模型并生成单数/复数的路由键。通过这种方式,`Person`类告诉Rails:“我就像`Contact`一样,问他就好了”。

这种解决方法被认为是处理STI子类路由问题的最佳实践,因为它简单且不会对其他Rails功能产生负面影响。

然而,也有一些人提出了这种解决方法可能会破坏Rails内部机制的担忧。但是,通过测试和实际使用的经验表明,这种解决方法并不会破坏模型之间的关系或STI模型的实例化。

除了以上解决方法外,还有其他一些替代方案被提出,例如部分重写`model_name`方法,或者使用`base_class.model_name`来指定父类模型。

总结起来,处理STI子类路由问题的最佳实践是重写子类的`model_name`方法,将其指向父类的`model_name`方法。这种解决方法简单有效,可以避免路由助手在STI子类中出现错误的路由生成。

0