Ошибка маршрутизации Rails для вложенного form_for - PullRequest
2 голосов
/ 07 декабря 2011

Меня сейчас об этом спрашивали тысячу раз, но это мне не помогает, хе :) Я был в этом часе.Моя форма:

= form_for @comment, :url_for => { :action => "create", :controller => "comments"}, :method => :post

мои рейк-маршруты:

                   POST   /t/:trunk_id/r/:root_id/comments(.:format)          {:action=>"create", :controller=>"comments"}
trunk_root_comment GET    /t/:trunk_id/r/:root_id/comments/:id(.:format)      {:action=>"show", :controller=>"comments"}

Ошибка:

undefined method `comments_path' for #<#<Class:0x007fed2c713128>:0x007fed2c71cc78>

Если я называю пространство формой:

= form_for [:trunk_root, @comment], :url_for => { :action => "create", :controller => "comments"}, :method => :post do |f|

который должен составить маршрут trunk_root_comments_path .. который является правильным в соответствии с маршрутами рейка .. Я получаю:

No route matches {:controller=>"comments", :format=>nil}

Помощь очень ценится .. смотрю на это в течение нескольких часов ..

ОБНОВЛЕНИЕ:

Спасибо Райан за такой отличный ответ!Очень четкое объяснение того, во что я просто «бросал вещи», теперь, по крайней мере, я понимаю лучше.На самом деле у меня уже был «trunk_root_comments_path» в моих рейк-маршрутах, и я попробовал пару комбинаций, о которых вы упомянули, но я не особо понял, чего мне не хватало, поэтому вы помогли.Я использую Mongo, и у меня на самом деле нет модели Trunk, у меня просто есть атрибут на корнях, называемый @ root.trunk, хотя у меня есть контроллер транка и, следовательно, он является частью моих маршрутов (возможно, плохая идея idk),

Итак, я попробовал ваш TLDR, и он сказал ошибку:

Undefined method 'root_comments_path'

.. потому что никакой модели Trunk не существует, я полагаю? .. поэтому я сделал @trunk просто равным правильному id с

= form_for [@trunk, @root, @comment] do |f| 

<- и я получил 'неопределенный метод' polit_root_comments_path '' .. Я понял хорошо ... это, вероятно, имеет смысл .., так как я терплю неудачу, я должен также попробовать вашу самую явную версию: </p>

= form_for @comment, :url => (trunk_root_comments_path(:trunk_id => @root.trunk, :root_id => @root.id)) do |f| 

и, конечно же, это сработало ... поэтому я не совсем уверен, как сделать это короче, чем это ... странно для меня, у меня есть другой вложенный ресурс "фотографии" на том же уровнеглубина маршрутов, и я смог заставить это работать с = form_for [: trunk_root, @photo],: html => {: class => 'root_form'} do | f | .. но здесь по какой-то причине я не могв любом случае, я бы сказал, что вы дали мне достаточно, чтобы понять 100%, но я думаю, что я перешел с 20% понимания до 50% понимания. Теперь я знаю, что id важны для маршрутов, и названным помощникам нужен доступ к ним.,Я получил представление о том, как работает url_helper, но мне нужно было бы прочитать больше о нем, чтобы я мог его полностью понять, я думаю.Я также теперь могу строить правильные маршруты в их более длинной форме, по крайней мере, чтобы пройти через сложные ситуации, подобные этой.Так что спасибо:)

Ответы [ 2 ]

10 голосов
/ 07 декабря 2011

TL; DR Вам необходимо указать и :trunk_id и root_id в своем URL или использовать form_for, например:

<%= form_for [@trunk, @root, @comment] do |f| %>

Rails пытается создать URL из хеша, который вы ему даете, но этот хеш ничего не соответствует в таблице маршрутизации. Вы можете сделать это:

{ :controller => "comments", :action => "create", :trunk_id => trunk.id, :root_id => root.id }

Но это действительно немного tl; dr .

Прохладный способ сделать это так:

trunk_root_comments_path(trunk, root)

Где trunk и root являются Trunk и Root экземплярами соответственно.

Теперь, если вы хотите быть супер-злой-крутой , сделайте это так:

<%= form_for [trunk, root, comment] do |f| %>

Наука!

Так как это работает? Элементарно, моя дорогая:

Rails сначала признает, что мы используем form_for, используя массив, и что мы имеем в виду бизнес . Rails использует этот переданный массив и строит из него URL. Это делается с помощью помощников маршрутизации, которые определены маршрутами. К сожалению, вы определили свои маршруты забавным образом, что не очень хорошо с этим работает, но не бойтесь! Мы можем это исправить.

То, как вы можете это сделать, это то, где у вас это есть в config/routes.rb:

post '/t/:trunk_id/r/:root_id/comments'

Вместо этого поставьте это:

post '/t/:trunk_id/r/:root_id/comments', :as => "trunk_root_comments"

Вы можете или уже иметь это:

match '/t/:trunk_id/r/:root_id/comments', :via => :post

Что должно стать таким:

match '/t/:trunk_id/r/:root_id/comments', :via => :post, :as => "trunk_root_comments"

В любом случае, теперь у вас есть не один, а два (!!) помощников пути, определенных маршрутами. Это trunk_root_comments_path и trunk_root_comments_url соответственно. Названия этих методов очень важны для того, что я собираюсь вам объяснить. Обратите внимание!

Итак, вернемся к нашему маленькому form_for звонку:

<%= form_for [trunk, root, comment] do |f| %>

Rails знает, что мы используем массив, потому что он может его видеть. То, что он делает с этим массивом, может казаться магическим, но на самом деле это не так.

Rails возьмет каждый элемент этого массива и создаст вспомогательный метод маршрутизации name из разных частей. На самом деле это не часть form_for, а другой метод с именем url_for, который вы можете использовать самостоятельно:

 url_for([trunk, root, comment])

В начале имя этого вспомогательного метода маршрутизации, генерируемое url_for, представляет собой просто пустой массив ([]). Ничего особенного.

Но то, что происходит , является особенным!

Первым элементом будет постоянный экземпляр класса Trunk. Под «постоянным» я подразумеваю, что это объект, который отображает непосредственно на запись в базе данных. Yay ORMs!

Rails узнает об этом и превратит помощника по маршрутизации в: [:trunk].

Вторым элементом будет постоянный экземпляр класса Root. Rails также знает это (черт, Rails - это smart !) И затем добавит это в массив, превратив его в [:trunk, :root]. Потрясающе.

Третий (и последний) элемент затем проверяется Rails. Он видит, что (в данном случае) это непостоянный элемент, то есть он не был сохранен в базе данных ... пока. Rails обрабатывает это по-другому и вместо этого добавляет [:comments] к массиву, превращая его в следующее:

[:trunk, :root, :comments]

Видите, куда я иду с этим сейчас?

Теперь, когда Rails выполнил свою задачу (или thang , если хотите), он объединит эти три части вместе, вот так: trunk_root_comments, и просто для правильной меры поместит _path в конце, превращая его в окончательного trunk_root_comments_path помощника.

А потом! Человек, а затем ... Rails вызывает этот метод и передает ему аргументы! Просто так:

trunk_root_comments_path(:trunk_id => trunk.id, :root_id => root_id)

Это генерирует полный путь к ресурсу, как это:

/t/:trunk_id/r/:root_id/comments

И БАМ! Полный круг! Именно так Rails узнает, что нужно сгенерировать URL, и вам больше не нужно использовать уродливые хэши.

Успех!

0 голосов
/ 07 декабря 2011

Не уверен, что этот маршрут настроен, но попробуйте:

= form_for @comment, :url => trunk_root_comments_path
...