форма для вложенных ресурсов
у меня есть вопрос из двух частей о form_for и вложенных ресурсах. Допустим, я пишу блог-движок и хочу связать комментарий со статьей. Я определил вложенный ресурс следующим образом:
map.resources :articles do |articles|
articles.resources :comments
end
форма комментария находится в шоу.формат html.erb view для статей, под самой статьей, например, так:
<%= render :partial => "articles/article" %>
<% form_for([ :article, @comment]) do |f| %>
<%= f.text_area :text %>
<%= submit_tag "Submit" %>
<% end %>
Это дает ошибку, " называется id для nil, который ошибочно и т. д."Я тоже пробовал
<% form_for @article, @comment do |f| %>
что делает правильно, но связывает f. text_area с полем "текст" статьи Вместо комментария и представляет html для статьи.текстовый атрибут в этой текстовой области. Так что я, кажется, тоже ошибаюсь. То, что я хочу, - это форма, в которой "submit" вызовет действие create на CommentsController, с article_id в параметрах, например, запрос post на /articles/1/comments.
вторая часть моего вопроса заключается в том, что это лучший способ создать экземпляр комментария для начала? Я создание @comment в действии show элемента управления ArticlesController, поэтому объект comment будет находиться в области действия помощника form_for. Затем в действии create CommentsController я создаю новый @comment, используя параметры, переданные из form_for.
спасибо!
3 ответа:
Трэвис Р прав. (Жаль, что я не могу выдвинуть тебя.) Я только что получил это работает сам. С помощью этих маршрутов:
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поставить для итерации,<%= link_to "delete", article_comment_path(@article, comment_item), :method => :delete, :confirm => "Really?" %>то, что говорит джамураа, может работать в контексте статьи, но это не сработало для меня в различных других пути.
существует много дискуссий, связанных с вложенными ресурсами, например http://weblog.jamisbuck.org/2007/2/5/nesting-resources
интересно, что я только что узнал, что большинство модульных тестов людей на самом деле не проверяют все пути. Когда люди следуют предложению джеймисбака, они в конечном итоге получают два способа получить вложенные ресурсы. Их юнит-тесты, как правило, получают / публикуют до самого простого:
# 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извините за долгий ответ. Не многие люди знают о тонкостях, я думаю.
убедитесь, что оба объекта созданы в контроллер:
@postи@commentдля поста, например:@post = Post.find params[:post_id] @comment = Comment.new(:post=>@post)затем в поле зрения:
<%= form_for([@post, @comment]) do |f| %>обязательно явно определите массив в form_for, а не только через запятую, как у вас выше.
вам не нужно делать специальные вещи в форме. Вы просто строите комментарий правильно в действии show:
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страница.