2010-01-09 2 views
106

У меня вопрос из двух частей о form_for и вложенных ресурсах. Допустим, я пишу движок блога, и я хочу связать комментарий к статье. Я определил вложенный ресурс следующим образом:form_for с вложенными ресурсами

map.resources :articles do |articles| 
    articles.resources :comments 
end 

Форма комментария в представлении show.html.erb для статей, под самой статье, к примеру, как это:

<%= render :partial => "articles/article" %> 
<% form_for([ :article, @comment]) do |f| %> 
    <%= f.text_area :text %> 
    <%= submit_tag "Submit" %> 
<% end %> 

Этот дает ошибку: «Вызывается id для нуля, что было бы ошибочно и т. д.» Я также попытался

<% form_for @article, @comment do |f| %> 

Что делает правильно, но относится к f.text_area «текст» полю артикля вместо комментария, и представляет HTML для атрибута article.text в этой области текста. Поэтому, похоже, я тоже ошибаюсь. То, что я хочу, - это форма, чья «submit» будет вызывать действие create в CommentsController со статьей_id в параметрах, например, запрос на отправку/articles/1/comments.

Вторая часть моего вопроса: как создать экземпляр комментария для начала? Я создаю @comment в действии show ArticlesController, поэтому объект комментария будет доступен для помощника form_for. Затем в действии createController, я создаю новый @comment, используя params, переданные из form_for.

Спасибо!

ответ

207

Travis R является правильным. (Хотелось бы, чтобы я мог упрекнуть тебя.) Я только что занялся этим. С помощью этих маршрутов:

resources :articles do 
    resources :comments 
end 

Вы получаете путь, как:

/articles/42 
/articles/42/comments/99 

маршрутизировать к контроллерам на

app/controllers/articles_controller.rb 
app/controllers/comments_controller.rb 

так же, как он говорит, в http://guides.rubyonrails.org/routing.html#nested-resources, без каких-либо специальных пространств имен.

Но частичные формы и формы становятся сложными. Обратите внимание на квадратные скобки:

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

Самое главное, если вы хотите URI, вам может понадобиться что-то вроде этого:

article_comment_path(@article, @comment) 

В качестве альтернативы:

[@article, @comment] 

, как описано в http://edgeguides.rubyonrails.org/routing.html#creating-paths-and-urls-from-objects

Например, внутри коллекций, частично с comment_item suppli ред для итерации

<%= link_to "delete", article_comment_path(@article, comment_item), 
     :method => :delete, :confirm => "Really?" %> 

Что jamuraa говорит, может работать в контексте статьи, но он не работает для меня различными другими способами.

Существует много дискуссий, связанных с вложенными ресурсами, например. http://weblog.jamisbuck.org/2007/2/5/nesting-resources

Интересно, что я только что узнал, что модульные тесты большинства людей фактически не проверяют все пути. Когда люди следуют предложению Jamisbuck, у них есть два способа получить доступ к вложенным ресурсам. Их блок-тесты, как правило, получить/пост к простейшему:

# POST /comments 
post :create, :comment => {:article_id=>42, ...} 

Для того, чтобы проверить маршрут, что они могут предпочесть, они должны сделать это таким образом:

# POST /articles/42/comments 
post :create, :article_id => 42, :comment => {...} 

Я узнал об этом, потому что мой блок-тесты начали неудачу, когда я перешел из этого:

resources :comments 
resources :articles do 
    resources :comments 
end 

к этому:

resources :comments, :only => [:destroy, :show, :edit, :update] 
resources :articles do 
    resources :comments, :only => [:create, :index, :new] 
end 

Я думаю, это нормально, если у вас есть повторяющиеся маршруты и пропустить несколько модульных тестов. (?. Почему проверить Потому что даже если пользователь не видит дубликаты, ваши формы могут ссылаться на них, или неявно с помощью именованных маршрутов) Тем не менее, чтобы свести к минимуму ненужного дублирования, я рекомендую это:

resources :comments 
resources :articles do 
    resources :comments, :only => [:create, :index, :new] 
end 

Извините за длинный ответ. Думаю, мало кто знает о тонкостях.

+0

Это работа, но мне пришлось изменить контроллер, как сказал jamuraa. –

+0

Путь Jam работает, но вы можете получить дополнительные маршруты, о которых вы, вероятно, не знаете. Лучше быть явным. – cdunn2001

+0

У меня были вложенные ресурсы, @result внутри @course. Хотя, '[@result, @course]' работал, но 'form_for (@result, url: {action:" create "})' также работает.Для этого требуется только имя последней модели и имя метода. – Anwar

33

Вам не нужно делать специальные вещи в форме. Вы просто построить комментарий правильно в шоу действия:

class ArticlesController < ActionController::Base 
    .... 
    def show 
    @article = Article.find(params[:id]) 
    @new_comment = @article.comments.build 
    end 
    .... 
end 

, а затем сделать форму для него с точки зрения статьи:

<% form_for @new_comment do |f| %> 
    <%= f.text_area :text %> 
    <%= f.submit "Post Comment" %> 
<% end %> 

по умолчанию, этот комментарий будет идти на create действия CommentsController , который вы, вероятно, захотите поставить redirect :back, чтобы вы перенаправлялись на страницу Article.

+9

Мне пришлось использовать формат 'form_for ([@ article, @new_comment])'. Я думаю, что это потому, что я показываю представление для 'comments # new', а не' article # new_comment'. Я фигурирую в статье 'article # new_comment' Rails достаточно умен, чтобы определить, что вложен объект комментария, и вам не нужно указывать его? – Soup

51

Убедитесь, что оба объекта, созданные в контроллере: @post и @comment на должность, например:

@post = Post.find params[:post_id] 
@comment = Comment.new(:post=>@post) 

Тогда в силу:

<%= form_for([@post, @comment]) do |f| %> 

Обязательно явно определить массив в form_for, а не только разделенные запятой, как вы уже выше.

+0

Travis's - это немного старый ответ, но я считаю, что это самый правильный вариант для Rails 3.2.X. Если вы хотите, чтобы все элементы построителя форм заполняли поля Comment, просто используйте массив, помощники URL не требуются. – Karl

+1

Установите только родительский объект, в котором действие вложено. Если вы только частично вложили ресурс (например, в соответствии с примером), то установка родительского объекта приведет к сбою form_for (подтвержденного с помощью рельсов 5.1) – iheggie

Смежные вопросы