rails form_with에서 nested form구현(accepts_nested_attributes_for)

Posted by negabaro kim on Sunday, May 3, 2020 Tags: rails tip   2 minute read

목표

post -> articles관계의 모델을 갱신할 수 있는 nested form을 구현해보자

컨트롤러 설정(new)

def new
    @post = current_user.posts.new
    @post.articles.build #이 부분이 포인트(없으면 fields_for :articles를 찾지못하고 아무것도 렌더링 안함)
end

뷰 설정

= form_with(model: @post, url: articles_path) do |f|
  = f.fields_for :articles do |b| #<< form_with 밑에서 fields_for
    = b.rich_text_area :content
  = f.submit '등록'

모델 설정

부모 모델에서 accepts_nested_attributes_for를 추가하는게 포인트 (참고로 has_many가 아니어도 동작함 has_one이라든가)

app/models/post.rb

class Post < ApplicationRecord
  has_many :articles
  accepts_nested_attributes_for :articles # <<이 부분을 추가
end

app/models/article.rb

class Article < ApplicationRecord
  belongs_to :post
end

컨트롤러 설정(create)

  def create
    article = current_user.posts.build(article_params)
    article.save
  end

  private
  def article_params
    params.require(:post).permit(articles_attributes: [:title, :content]) # 모델명_attributes라고 적어주는게 포인트
  end

위 설정이 문제없다면 nested한 폼 작성완료

메모1

브라우저에서 보면

<textarea name="post[articles_attributes][0][content]" id="post_articles_attributes_0_content"></textarea>

이런식으로 렌더링됨

= f.fields_for :articles do |b|부분에서 :articles을 :test로 바꾸면 아래와 같이 렌더링 됨

<textarea name="post[test][content]" id="post_article_content"></textarea>

궁금해서

= f.fields_for 'articles_attributes[0]' do |b|로 변경해서 브라우저에서 확인

<textarea name="post[articles_attributes[0]][content]" id="post_articles_attributes_0__content"></textarea>

이렇게 기술해도 정상작동함 has_many의 모델명을 적어주면 알아서 네이밍까지 만들어주니 맞춰주도록 하자

메모2

컨트롤러 설정(new)부분에서

@post.articles.build 부분이 없으면 = f.fields_for :articles do |b|가 정상작동하지 않으므로 주의 에러가 나는것도 아니고 아에 렌더링 자체가 안됨

reference:

https://ruby-rails.hatenadiary.com/entry/20141208/1418018874