web-dev-qa-db-ja.com

Ruby on Rails:単一のリソースとform_for

ユーザーのセッションに接続されている注文を1つだけ使用してユーザーに働きたい。注文に単一のリソースを設定しました

routes.rb:

resource :order

views/orders/new.html.erb:

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

しかし、新しい注文ページを開くと、エラーが発生します。

undefined method `orders_path`

:url => order_path in form_for、しかしこの衝突を解決する真の方法は何ですか?

62
petRUShka

残念ながら、これは バグ です。あなたが言うようにあなたはURLを設定する必要があります。

= form_for @order, :url => orders_path do |f|
58
mckeed

その魔法の道はどこから来るのですか?

多くのトレースが必要でしたが、最終的にurl_forがActionDispatch :: Routing :: PolymorphicRoutesで定義されたpolymorphic_pathメソッドを使用してモデルのパスを決定することがわかりました。 polymorphic_pathは、次の行に沿って何かを呼び出すことにより、最終的にモデルのオートマジックパスを取得します。

record.class.model_name.route_key

私は少し単純化していますが、これは基本的にそれです。配列(form_for[@order, @item]など)がある場合、上記は各要素で呼び出され、結果は_で結合されます。


クラスの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 %>

やってみよう!

49
jshkol