formularz dla zasobów zagnieżdżonych

Mam dwuczęściowe pytanie dotyczące form_for i zagnieżdżonych zasobów. Powiedzmy, że piszę silnik bloga i chcę odnieść komentarz do artykułu. Zdefiniowałem zagnieżdżony zasób w następujący sposób:

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

Formularz komentarza jest w programie.html.widok erb dla artykułów, pod samym artykułem, na przykład tak:

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

To daje błąd, " zwany id dla nil, który błędnie itp."I' ve also tried

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

Który renderuje poprawnie, ale odnosi się f. text_area do pola "tekst" artykułu zamiast komentarza i prezentuje html dla artykułu.atrybut tekstowy w tym obszarze tekstowym. Więc chyba też się mylę. Chcę formularza, którego 'submit' wywoła akcję create na CommentsController, z article_id w params, na przykład żądanie post do / articles / 1 / comments.

Druga część mojego pytania brzmi: jaki jest najlepszy sposób na stworzenie instancji komentarza na początek? Tworzę @komentarz w pokazuje działanie kontrolera ArticlesController, tak aby obiekt comment znajdował się w zasięgu helpera formula_for. Następnie w akcji create kontrolera CommentsController, tworzę nowy @ comment używając param przekazywanych z formula_for.

Dzięki!
Author: Dave Sims, 2010-01-09

3 answers

Travis R ma rację. (Szkoda, że nie mogę ci pomóc. Sam to naprawiłem. Z tymi trasami:

resources :articles do
  resources :comments
end

Dostajesz ścieżki typu:

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

Przekierowanie do kontrolerów na

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

Tak jak jest napisane na http://guides.rubyonrails.org/routing.html#nested-resources , bez specjalnych przestrzeni nazw.

Ale częściowe i formy stają się trudne. Zwróć uwagę na nawiasy kwadratowe:

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

Najważniejsze, jeśli chcesz URI, możesz potrzebować czegoś takiego jak to:

article_comment_path(@article, @comment)

Alternatywnie:

[@article, @comment]

Jak opisano w http://edgeguides.rubyonrails.org/routing.html#creating-paths-and-urls-from-objects

Na przykład wewnątrz zbioru częściowego z comment_item dostarczonego do iteracji,

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

To, co mówi jamuraa, może działać w kontekście artykułu, ale nie działało dla mnie na różne inne sposoby.

Istnieje wiele dyskusji związanych z zagnieżdżonymi zasobami, np. http://weblog.jamisbuck.org/2007/2/5/nesting-resources

Co ciekawe, właśnie dowiedziałem się, że większość ludzi testy jednostkowe nie sprawdzają wszystkich ścieżek. Kiedy ludzie podążają za sugestią jamisbucka, kończą na dwóch sposobach dotarcia do zagnieżdżonych zasobów. Ich testy jednostkowe zazwyczaj dostają / wysyłają do najprostszych:

# POST /comments
post :create, :comment => {:article_id=>42, ...}
Aby przetestować trasę, którą mogą preferować, muszą zrobić to w ten sposób:]}
# POST /articles/42/comments
post :create, :article_id => 42, :comment => {...}

Nauczyłem się tego, ponieważ moje testy jednostkowe zaczęły awaria gdy przesiadłem się z tego:

resources :comments
resources :articles do
  resources :comments
end

Do tego:

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

Myślę, że jest ok mieć duplikaty tras, i przegapić kilka testów jednostkowych. (Dlaczego test? Ponieważ nawet jeśli użytkownik nigdy nie widzi duplikatów, formularze mogą się do nich odnosić, w sposób dorozumiany lub za pomocą nazwanych tras.) Jednak, aby zminimalizować zbędne powielanie, polecam to:

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

Przepraszam za długą odpowiedź. Myślę, że niewielu ludzi zdaje sobie sprawę z subtelności.

 211
Author: cdunn2001,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-06 15:21:36

Upewnij się, że oba obiekty zostały utworzone w kontrolerze: @post i @comment dla posta, np:

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

Następnie w widoku:

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

Upewnij się, że jawnie zdefiniujesz tablicę w formula_for, a nie tylko rozdzielone przecinkami, jak powyżej.

 52
Author: Travis Reeder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-09 19:56:27

Nie musisz robić specjalnych rzeczy w formie. Wystarczy poprawnie zbudować komentarz w akcji show:

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

A następnie zrób dla niego formularz w widoku artykułu:

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

Domyślnie ten komentarz trafi do create akcji CommentsController, w którą prawdopodobnie będziesz chciał umieścić redirect :back, aby przekierować cię z powrotem na stronę Article.

 33
Author: jamuraa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-10 00:08:52