65

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

路线.rb:

resource :order

意见/订单/new.html.erb:

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

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

undefined method `orders_path`

我知道,我可以设置:url => order_pathform_for但是解决这种冲突的真正方法是什么?

4

2 回答 2

61

不幸的是,这是一个错误。您必须像您提到的那样设置网址。

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

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


更新

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

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

然后,当该polymorphic_url方法被赋予一个类名为“Order”的对象时,它将[:order]用作 url 组件,而不是像jskol 的回答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
于 2010-09-17T18:26:03.987 回答
52

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

我花了很多时间进行跟踪,但我最终发现 url_for 使用ActionDispatch::Routing::PolymorphicRoutespolymorphic_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 %>

试试看!

于 2013-04-26T05:09:25.810 回答