Skip to main content

How do I create a parent record from the child when the parent doesn't exist?

Rails • Asked by Nino Rosella

Hi team,

I've trying to model books, chapters, and notes.

I have the following:

class Book < ApplicationRecord
    has_many :chapters
    has_many :notes
end
class Chapter < ApplicationRecord
    belongs_to :book
    has_many :notes
end
class Note < ApplicationRecord
    belongs_to :chapter
end

I can create Books and notes just fine.

What I want to do when creating a new Note is either create a new Chapter or assign an existing one to a note. Said another way: I'm trying to create a parent from the child before the parent even exists, or assigning an exising parent to the child.

This is the kind of functionality that's provided by gems such as acts_as_taggable_on. I've tried using nested forms, but just couldn't get it near to what I wanted. I'm wondering if my architecture is even correct for this type of use? Any guidance you could provide would be much appreciated.


I mananged to solve this. Here's what I did for anyone that comes across this in the future. Note in the new action I have @note.build_chapter rather than @note.chapter.build

class Book < ApplicationRecord
    has_many :chapters
    has_many :notes
end
class Chapter < ApplicationRecord
    belongs_to :book
    has_many :notes
end
class Note < ApplicationRecord
    belongs_to :chapter, optional: true
  accepts_nested_attributes_for :chapter
end
class NotesController < ApplicationController
    def new
        @note = Note.new
        @note.build_chapter
    end

    def create
        @book = Book.find(params[:book_id])
        @note = @book.notes.create(note_params)

        if params[:book_note][:chapter_name]
            parent_chapter = @book.chapters.find_or_create_by(name: params[:note][:chapter_name], book_id: params[:book_id])
            @note.chapter = parent_chapter
        end
    end

    private

    def book_note_params
        params.require(:book_note).permit(:title, :body,  : chapters_attributes: [:id, :name, :chapter_id, :_destroy])
    end

end

The controllers need refactoring, but you get the gist.


Login or Create An Account to join the conversation.

Subscribe to the newsletter

Join 20,000+ developers who get early access to new screencasts, articles, guides, updates, and more.

    By clicking this button, you agree to the GoRails Terms of Service and Privacy Policy.

    More of a social being? We're also on Twitter and YouTube.