【问题标题】:Ruby on rails: singular resource and form_forRuby on rails:单一资源和 form_for
【发布时间】:2011-04-13 19:11:19
【问题描述】:

我希望用户只使用一个连接到用户会话的订单。所以我为订单设置了单一资源

routes.rb:

resource :order

视图/订单/new.html.erb:

<%= form_for @order do |f| %>
   ...
<% end %>

但是当我打开新订单页面时出现错误:

undefined method `orders_path`

我知道,我可以在form_for中设置:url =&gt; order_path,但是解决这个冲突的真正方法是什么?

【问题讨论】:

  • 我不确定我是否明白你为什么不对资源使用单数
  • 因为rails guide建议使用控制器的复数形式。但是在单数形式的控制器中存在相同的错误......
  • 如果您只有一个单一的嵌套资源给您带来问题,您可以使用form_for [@user, :subscription, @payment]user_subscription_payment_path(@user, @payment) 生成路径,例如action="/users/21/subscription/payments/29"

标签: ruby-on-rails resources router form-for singular


【解决方案1】:

很遗憾,这是a bug。您必须像您提到的那样设置网址。

= form_for @order, :url => order_path do |f|

请注意,这将正确路由到 createupdate,具体取决于 @order 是否被持久化。


更新

现在还有另一种选择。您可以将其添加到您的路线配置中:

resolve("Order") { [:order] }

然后当polymorphic_url 方法被赋予一个类名为“Order”的对象时,它将使用[:order] 作为url 组件,而不是像jskol's answer 中描述的那样调用model_name.route_key

这有一个限制,它不能在范围或命名空间内使用。您可以在路由配置的顶层路由命名空间模型:

resolve('Shop::Order') { [:shop, :order] }

但是它不会对带有额外组件的路由产生影响,所以

url_for(@order)           # resolves to shop_order_url(@order)
url_for([:admin, @order]) # resolves to admin_shop_orders_url(@order) 
                          #        note plural 'orders' ↑
                          #        also, 'shop' is from module name, not `resolve` in the second case

【讨论】:

【解决方案2】:

那条神奇的路径从何而来?

我进行了大量跟踪,但最终我发现 url_for 使用 ActionDispatch::Routing::PolymorphicRoutes 中定义的 polymorphic_path 方法确定模型的路径。 polymorphic_path 最终通过调用类似以下内容的方式为您的模型获取自动路径:

record.class.model_name.route_key

我稍微简化了一点,但基本上就是这样。如果您有一个数组(例如form_for[@order, @item]),则在每个元素上调用上述内容,并将结果与​​_ 连接起来。


您的 Class 上的 model_name 方法来自 ActiveRecord::Naming

module ActiveModel
  ...
  module Naming
    ...
    def model_name
      @_model_name ||= begin
        namespace = self.parents.detect do |n|
          n.respond_to?(:use_relative_model_naming?) && 
                                                 n.use_relative_model_naming?
        end
        ActiveModel::Name.new(self, namespace)
      end
    end
  end
end


如何更改?

幸运的是,ActiveModel::Name 预先计算了包括 route_key 在内的所有值,因此要覆盖该值,我们所要做的就是更改实例变量的值。

对于您问题中的:order 资源:

class Order < ActiveRecord::Base
  model_name.instance_variable_set(:@route_key, 'order')
  ...
end

# new.html.erb
<%= form_for @order do |f| # Works with action="/order" %>
    ...
<% end %>

试试看!

【讨论】:

  • @aidan 谢谢!当我自己遇到这个问题时,另一个答案已经被接受了一段时间。
  • 这是一个超级 rad 答案的大量调查。要走的路。
  • 这是忍者回答。
  • 对于无法显式设置 url 选项的多态奇异资源,这是唯一简单的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-21
相关资源
最近更新 更多