在 Rails 5.1 中预填充嵌套表单时 HTML 不正确

Incorrect HTML when pre-populating nested forms in Rails 5.1

我有一个使用 Google 书籍 API 的 Rails 5.1 应用程序,我需要在表单中预填充嵌套字段。有两种方法可以创建 Book

首先,通过正常的 /books/new 形式,accepts_nested_attributes_for :authorshas_many: through 关联。我在这里使用 cocoon gem 并且一切正常。

其次,用户可以通过使用 ISBN 号搜索 Google 本书 API 来创建 Book。然后,此数据会在提交给 BooksController 中的 create 操作之前预填充表单。除了能够正确提交嵌套的 Author 数据之外,我已经成功地完成了这项工作。

我目前让每个作者在表单中填充一个字段,但是当我提交数据时,只有作者数组中的最后一项(对于有多位作者的书)被保存。

我认为这是因为表单 html 的两个字段具有相同的 nameid,如下所示。我如何获得此表单以提交两位作者?

<input value="John J. Ratey" type="text" name="book[authors_attributes][0][name]" id="book_authors_attributes_0_name">
<input value="Richard Manning" type="text" name="book[authors_attributes][0][name]" id="book_authors_attributes_0_name">

books_controller.rb

class BooksController < ApplicationController

before_action :authenticate_user!
before_action :set_book, except: [:index, :new, :create, :new_book, :submit_book]

def create
    @book = current_user.books.create(book_params)
    @book.authors.each {|author| author.user_id = current_user.id}

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

def new_book
end

def submit_book
    @book = Book.new
    @book.authors.new
    @response = GoogleBooks.new(params[:q], @book)
end

private

    def set_book
        @book = Book.find(params[:id])
    end

    def book_params
        params.require(:book).permit(:title, :subtitle, :description, author_ids:[], authors_attributes: [:id, :name, :_destroy])
    end

end

book.rb

class Book < ApplicationRecord
  has_many :book_authors
  has_many :authors, through: :book_authors

  accepts_nested_attributes_for :authors, allow_destroy: true

  validates :title, presence: true
  validates_associated :authors
end

google_books.rb

class GoogleBooks
  include HTTParty
  base_uri 'https://www.googleapis.com/books/v1'

  def initialize(isbn, book)
    @query = self.class.get("/volumes?q=isbn:#{isbn}")
    @book = book
  end

  def title
    @query['items'].first['volumeInfo']['title']
  end

  def subtitle
    @query['items'].first['volumeInfo']['subtitle']
  end

  def description
    @query['items'].first['volumeInfo']['description']
  end

  def authors
    @query['items'].first['volumeInfo']['authors']
    #=> ['John J. Ratey', 'Richard Manning']
  end

end

submit_book.html.erb

<%= form_for @book do |f| %>
  <%= f.text_field :title, value: @response.title %>
  <%= f.text_field :subtitle, value: @response.subtitle %>
  <%= f.text_field :description, value: @response.description %>

  <%= f.fields_for :authors, @book.authors.build do |authors_fields| %>
    <% @response.authors.each do |author| %>
      <%= authors_fields.text_field :name, value: author %>
    <% end %>
  <% end %>

<%= f.submit %>

解决了。

是一个改变的案例

<%= f.fields_for :authors, @book.authors.build do |authors_fields| %>
  <% @response.authors.each do |author| %>
    <%= authors_fields.text_field :name, value: author %>
  <% end %>
<% end %>

至此

<% @response.authors.each do |author| %>
  <%= f.fields_for :authors, @book.authors.build do |authors_fields| %>
    <%= authors_fields.text_field :name, value: author %>
  <% end %>
<% end %>

产生以下正确的HTML:

<input value="John J. Ratey" type="text" name="book[authors_attributes][0][name]" id="book_authors_attributes_0_name">
<input value="Richard Manning" type="text" name="book[authors_attributes][1][name]" id="book_authors_attributes_1_name">