Как сохранить данные, используя вложенные ресурсы? - PullRequest
0 голосов
/ 09 января 2019

Я практикуюсь на Rails и испытываю трудности с вложенными ресурсами. У меня есть авторы, книги и жанры в моей БД. Я добавил вложенный ресурс на routes.rb:

  resources :authors do
    resources :books
  end

Я вижу новый маршрут по rake routes: new_author_book.

Я добавил ссылку на автора - show.html.erb:

<%= link_to "Add a Book to This Author" , new_author_book_path(@author) %>

Так что эта ссылка перенаправляет меня на http://localhost:3000/authors/[author_id]/books/new

Я могу правильно увидеть author_id, используя params[:author_id] в new.html.erb (Books)

Я пытался найти этого автора в books_controller, используя:

def create
  @author = Author.find(params[:author_id])
  @book = @author.book.create(book_params)
end

Но ошибка возникает как Couldn't find Author without an ID

Я использовал леса для создания этих таблиц и связей.

Это мой _form.html.erb частичный (Книги)

<%= form_with(model: book, local: true) do |form| %>
  <% if book.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(book.errors.count, "error") %> prohibited this book from being saved:</h2>

      <ul>
      <% book.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= form.label :name %>
    <%= form.text_field :name %>
  </div>

  <div class="field">
    <%= form.label :release %>
    <%= form.text_field :release %>
  </div>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

Это books_contollers#new,

  def new
    @book = Book.new
  end

ПОСЛЕДНЕЕ СОСТОЯНИЕ ПРИЛОЖЕНИЯ:

books_controller.rb :

  def new
    @author = Author.find(params[:author_id])
    @book = @author.books.new
  end

 def create
  @book = Book.create(book_params)
    respond_to do |format|
      if @book.save
        format.html { redirect_to @book, notice: 'Book was successfully created.' }
        format.json { render :show, status: :created, location: @book }
      else
        format.html { render :new }
        format.json { render json: @book.errors, status: :unprocessable_entity }
      end
    end
  end

Ответ сервера:

Started POST "/authors/11/books" for 127.0.0.1 at 2019-01-10 13:37:21 +0300
Processing by BooksController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"SHORTENED_THIS==", "book"=>{"name"=>"Shiny Tales", "release"=>"2011", "genre_id"=>"1"}, "commit"=>"Create Book", "author_id"=>"11"}
   (0.1ms)  BEGIN
  ↳ app/controllers/books_controller.rb:29
  Genre Load (0.2ms)  SELECT  `genres`.* FROM `genres` WHERE `genres`.`id` = 1 LIMIT 1
  ↳ app/controllers/books_controller.rb:29
   (0.2ms)  ROLLBACK
  ↳ app/controllers/books_controller.rb:29
   (0.1ms)  BEGIN
  ↳ app/controllers/books_controller.rb:31
   (0.1ms)  ROLLBACK
  ↳ app/controllers/books_controller.rb:31
  Rendering books/new.html.erb within layouts/application
  Rendered books/_form.html.erb (1.8ms)
  Rendered books/new.html.erb within layouts/application (2.8ms)
Completed 200 OK in 32ms (Views: 20.0ms | ActiveRecord: 1.3ms)

Я попытался следовать Руководству по Rails, добавив вторую модель раздел, но я думаю, что это немного по-другому.

Я не хочу делать какой-либо выбор автора или что-то подобное в этой ситуации, потому что я уже выбрал автора в авторе - show.html.erb

Ответы [ 3 ]

0 голосов
/ 09 января 2019

1: Во-первых, самый чистый метод будет:

form_with(model: @author, url: (@book.new_record? ? [@author, @book]: @book))

Это приведет к созданию / обновлению пути к книге с помощью author_id. И в вашем контроллере:

def create
  @author = Author.find(params[:author_id])
  @book = @author.book.create(book_params)
end

2: В противном случае вы можете добавить скрытое поле в существующую форму, например:

<%= form.hidden_field :author_id, params[:author_id] %>

и в вашем контроллере:

def create
  @book = Book.create(book_params)
end
0 голосов
/ 10 января 2019

Наконец я решил проблему, создав пользовательскую функцию в виде set_author в books_controller

class BooksController < ApplicationController
  before_action :set_book, only: [:show, :edit, :update, :destroy]
  before_action :set_author , only: [:new,:create]

  def new
    @book = Book.new
  end

  def create
    @book = Book.create(book_params)
    @book.author_id = @author.id
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_book
      @book = Book.find(params[:id])
    end

    def set_author
      @author = Author.find(params[:author_id])
    end
end
0 голосов
/ 09 января 2019

Похоже, здесь нужна небольшая перетасовка. Я полагаю, что ваши действия new и create неверны.

params[:author_id] доступно для вашего действия new, которое должно выглядеть примерно так:

def new
  @author = Author.find(params[:author_id])
  @book = @author.books.new
end

И тогда create должно быть:

def create
  @book = Book.create(book_params)
end

Возможно, вам понадобится поле в вашей форме book для author_id, хотя я не могу вспомнить, насколько это необходимо. Например:

<%= form.hidden_field :author_id, book.author_id %>

При этом убедитесь, что author_id внесен в белый список в параметрах books_controllers:

def book_params
  params.require(:book).permit(:author_id, ... the rest of your attributes)
end

Кроме того, ваша форма должна быть обновлена, чтобы указывать на вложенный ресурс ( здесь документов), который предоставит params[:author_id] вашему действию create, что означает, что вы можете оставить все как есть. Вы просто передаете массив конструктору форм, т.е.

<%= form_with(model: [@author, @book]) do |form| %>

Устанавливает форму для попадания на вложенный URL с параметром author_id на месте.

Если следовать этому подходу, ваше действие create должно выглядеть следующим образом:

def create
  @author = Author.find(params[:author_id])
  @book = @author.books.create(book_params)
end

Надеюсь, что-то там поможет, дайте мне знать, как вы поживаете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...