All threads / Form item disappearing when failing nested validations

Ask A Question

Notifications

You’re not receiving notifications from this thread.

Form item disappearing when failing nested validations

Nino Rosella asked in Rails

I have a Rails 5 app, and I'm having a problem with validations using the Cocoon gem with nested, dynamic forms. 

When a validation on my Book model fails, and my create action renders :new, the Authorfield disappears from my new book form.

One thing I've noticed is that when the validation fails, rather than passing authors back into my form, it's passing book_authors back because of the line @book.book_authors.build(author_id: author.id) in my create action. Pretty sure this is the cause of my issue, but don't know how to fix it.

books_controller.rb

class BooksController < ApplicationController
...

def new
@book = Book.new
@book.authors.build
end

def create
@book = current_user.books.create(book_params)
params[:book][:authors_attributes].each do |k,v|
author = Author.find_or_create_by(name: v['name'], user_id: current_user.id)
@book.book_authors.build(author_id: author.id)
end

if @book.save
    redirect_to book_path(@book)
else
  render :new
end

end

private

def book_params
params.require(:book).permit(:title, :published_city, :description, author_ids:[])
end

def author_params
params.require(:book).permit(authors_attributes: [:id, :name, :_destroy])
end
end

book.rb

class Book < ApplicationRecord

has_many :book_authors
has_many :authors, through: :book_authors
belongs_to :user

accepts_nested_attributes_for :authors, allow_destroy: true
validates :title, :published_city, presence: true
validates_associated :authors, inverse_of: :book
end

book_author.rb

class BookAuthor < ApplicationRecord
belongs_to :book
belongs_to :author
end
author.rb

class Author < ApplicationRecord
has_many :book_authors
has_many :books, through: :book_authors

validates :name, presence: true
end

new.html.erb

<%= form_for @book do |f| %>
<%= f.text_field :title, required: true %>
<%= f.text_area :description %>
<div id='authors'>
<%= f.fields_for :authors do |author| %>
<%= render 'author_fields', :f => author %>
<% end %>
<div class='links'>
<%= link_to_add_association 'Add another author', f, :authors %>
</div>
</div>
<%= f.text_field :published_city %>
<%= f.submit %>
<% end %>
Hey your `create` action shouldn't need to loop over the `book_params` to create params.

I quickly created a sample app that shows how I use `cocoon` with many-to-many relationships.

It is at https://github.com/dylanpinn/rails-bookstore. Let me know how you go.
Hey Dylan,

Just want to thank you for going to the effort to build this! Love the GoRails community.

However, when I run that code and create a new book, but leave the author field blank, it doesn't seem to be hitting the validation. So I'm able to create a book with no author. Any ideas why this might be?
Try adding `validates :authors, presence: true` to the Book model.
Yep, works a charm.

Thank you so much Dylan.
Join the discussion

Want to stay up-to-date with Ruby on Rails?

Join 34,885+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.

    logo Created with Sketch.

    Ruby on Rails tutorials, guides, and screencasts for web developers learning Ruby, Rails, Javascript, Turbolinks, Stimulus.js, Vue.js, and more. Icons by Icons8

    © 2020 GoRails, LLC. All rights reserved.