Rails 3: Как создать новый вложенный ресурс?

"Руководство по началу работы с Rails" , заглядывая в эту часть, поскольку оно не реализует "новое" действие контроллера комментариев. В моем приложении у меня есть модель книги, которая имеет много глав:

class Book < ActiveRecord::Base
  has_many :chapters
end

class Chapter < ActiveRecord::Base
  belongs_to :book
end

В файле маршрутов:

resources :books do
  resources :chapters
end

Теперь я хочу реализовать "новое" действие контроллера Chapters:

class ChaptersController < ApplicationController
  respond_to :html, :xml, :json

  # /books/1/chapters/new
  def new
    @chapter = # this is where I'm stuck
    respond_with(@chapter)
  end

Каков правильный способ сделать это? Кроме того, как выглядит вид script (форма)?

Ответ 1

Сначала вы должны найти соответствующую книгу в своем главном контроллере, чтобы построить для него главу. Вы можете выполнять следующие действия:

class ChaptersController < ApplicationController
  respond_to :html, :xml, :json

  # /books/1/chapters/new
  def new
    @book = Book.find(params[:book_id])
    @chapter = @book.chapters.build
    respond_with(@chapter)
  end

  def create
    @book = Book.find(params[:book_id])
    @chapter = @book.chapters.build(params[:chapter])
    if @chapter.save
    ...
    end
  end
end

В вашей форме new.html.erb

form_for(@chapter, :url=>book_chapters_path(@book)) do
   .....rest is the same...

или вы можете попробовать стенографию

form_for([@book,@chapter]) do
    ...same...

Надеюсь, что это поможет.

Ответ 2

Попробуйте @chapter = @book.build_chapter. Когда вы вызываете @book.chapter, оно равно нулю. Вы не можете сделать nil.new.

EDIT: Я только понял, что книга, скорее всего, имеет несколько глав... выше для has_one. Вы должны использовать @chapter = @book.chapters.build. Главы "пустой массив" на самом деле представляют собой специальный объект, который отвечает на build для добавления новых ассоциаций.

Ответ 3

Возможно, несвязанный, но из этого вопроса вы можете приехать сюда, чтобы посмотреть, как сделать что-то немного другое.

Предположим, вы хотите сделать Book.new(name: 'FooBar', author: 'SO'), и хотите разбить некоторые метаданные на отдельную модель, называемую readable_config, которая является полиморфной и хранит name и author для нескольких моделей.

Как вы принимаете Book.new(name: 'FooBar', author: 'SO') для сборки модели Book, а также модели readable_config (которую я, возможно, ошибочно назвал бы "вложенным ресурсом" )

Это можно сделать так:

class Book < ActiveRecord::Base
  has_one :readable_config, dependent: :destroy, autosave: true, validate: true
  delegate: :name, :name=, :author, :author=, :to => :readable_config

  def readable_config
    super ? super : build_readable_config
  end
end