Рубин на рельсах: единый ресурс и form_for - PullRequest
60 голосов
/ 17 сентября 2010

Я хочу, чтобы пользователь работал только с одним заказом, связанным с сеансом пользователя.Поэтому я установил единый ресурс для порядка

rout.rb:

resource :order

views / orders / new.html.erb:

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

Но когда я открываюНа новой странице заказа появляется сообщение об ошибке:

undefined method `orders_path`

Я знаю, что могу установить :url => order_path в form_for, но каков истинный способ разрешения этого столкновения?

Ответы [ 2 ]

58 голосов
/ 17 сентября 2010

К сожалению, это ошибка . Вам нужно установить URL, как вы упомянули.

= form_for @order, :url => orders_path do |f|
49 голосов
/ 26 апреля 2013

Откуда взялся этот магический путь?

Мне потребовалось много трассировки, но я в конечном итоге обнаружил, что url_for определяет путь для вашей модели, используя метод polymorphic_path, определенный в ActionDispatch:: Маршрутный :: PolymorphicRoutes .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 %>

Попробуйте!

...