중첩 된 자원이있는 form_for


125

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 %>

이것은 오류, "Called id for nil, 이것은 실수로 등이 될 것입니다." 나는 또한 시도했다

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

올바르게 렌더링되지만 f.text_area를 댓글 대신 기사의 '텍스트'필드와 관련시키고 해당 텍스트 영역의 article.text 속성에 대한 html을 표시합니다. 그래서 나는 이것도 잘못된 것 같습니다. 내가 원하는 것은 '제출'이 CommentsController에 대한 생성 작업을 호출하는 양식입니다. 예를 들어 / articles / 1 / comments에 대한 게시 요청과 같이 params에 article_id가 있습니다.

내 질문의 두 번째 부분은 시작하는 주석 인스턴스를 만드는 가장 좋은 방법은 무엇입니까? ArticlesController의 show 작업에서 @comment를 만들고 있으므로 주석 개체는 form_for 도우미의 범위에 있습니다. 그런 다음 CommentsController의 생성 작업에서 form_for에서 전달 된 매개 변수를 사용하여 새 @comment를 생성합니다.

감사!

답변:


228

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반복을 위해 제공된 부분 컬렉션 내부 에서

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

jamuraa가 말하는 것은 Article의 맥락에서 작동 할 수 있지만 다른 다양한 방식으로는 작동하지 않았습니다.

중첩 된 리소스와 관련된 많은 토론이 있습니다. 예 : 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

긴 답변에 대해 죄송합니다. 미묘함을 아는 사람은 많지 않은 것 같습니다.


Work이지만, jamuraa가 말한 것처럼 컨트롤러를 수정해야했습니다.
Marcus Becker

Jam의 방식은 작동하지만 아마 모르는 추가 경로로 끝날 수 있습니다. 명시하는 것이 좋습니다.
cdunn2001 2014-06-28

@course 내에 중첩 된 리소스, @result가 있습니다. 비록, [@result, @course]일, 그러나 form_for(@result, url: { action: "create" }) 또한 작동합니다. 여기에는 마지막 모델 이름과 메서드 이름 만 필요합니다.
안와르

@ cdunn2001 여기에 "@article"을 이렇게 언급해야하는 이유와 이것이 무엇을 의미하는지 설명해 주시겠습니까? 아래 구문은 무엇을합니까? : <% = form_for [@article, @comment] do | f | %>
Arpit 아가 왈

1
Travis / @ cdunn2001이 맞았습니다. 중복없이 중첩 된 경로를 사용할 때 부모와 리소스를 모두 설정하지 마십시오. 그렇지 않으면 모든 작업이 중첩 된 것으로 간주됩니다. 마찬가지로 모든 것을 중첩했다면 항상 AT.parent를 설정하십시오. 또한 부분적으로 중첩 된 경로가있는 취소 버튼이있는 공통 양식이있는 경우 다음과 같은 경로를 사용하여 설정 한대로 작동하도록합니다 (자식의 복수화에주의) : <% = link_to 'Cancel', parent_children_path (AT.parent || AT.child.parent) %>
iheggie

54

controller : @post@comment포스트에 대해 두 객체가 모두 생성되었는지 확인하십시오. 예 :

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

그런 다음보기 :

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

위와 같이 쉼표로 구분 된 것이 아니라 form_for에 배열을 명시 적으로 정의해야합니다.


Travis 's는 약간 오래된 답변이지만 Rails 3.2.X에 가장 적합하다고 생각합니다. 양식 작성기의 모든 요소가 Comment 필드를 채우도록하려면 배열을 사용하십시오. URL 도우미는 필요하지 않습니다.
Karl

1
액션이 중첩 된 상위 개체 만 설정합니다. 리소스를 부분적으로 만 중첩 한 경우 (예 : 예에 따라) 부모 개체를 설정하면 form_for가 실패합니다 (지금 바로 rails 5.1에서 다시 확인 됨)
iheggie

35

양식에서 특별한 일을 할 필요가 없습니다. 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페이지.


10
나는 form_for([@article, @new_comment])형식 을 사용해야했다 . 나는 이것이 comments#new아니라에 대한 견해를 보여주기 때문이라고 생각합니다 article#new_comment. 나는 그림 article#new_comment레일은 주석 객체가 중첩되고, 그러한 당신이 그것을 지정할 필요가 없습니다 것을 해결하기 위해 스마트 충분하다?
수프
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.