我正在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
通过在new.html.erb(Books)中使用params[:author_id]
,我可以正确看到author_id
我尝试使用以下方法在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指南添加第二个模型 部分,但我认为这有点不同。
在这种情况下,我不想进行任何作者选择,因为我已经在author-show.html.erb
中选择了一位作者
答案 0 :(得分:2)
在我看来,这里需要进行一些改组。我相信您的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
此外,您的表单应更新为指向嵌套资源(docs here),它将为您的params[:author_id]
操作提供create
,这意味着您可以保持原样。您只需将数组传递给表单生成器,即
<%= form_with(model: [@author, @book]) do |form| %>
这将设置表单以按需使用author_id
参数的嵌套URL。
如果采用这种方法,您的create
操作应如下所示:
def create
@author = Author.find(params[:author_id])
@book = @author.books.create(book_params)
end
希望那里有帮助-让我知道你的生活。
答案 1 :(得分:0)
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 :否则,您可以在现有表单中添加hidden_field,例如:
<%= form.hidden_field :author_id, params[:author_id] %>
并在您的控制器中:
def create
@book = Book.create(book_params)
end
答案 2 :(得分:0)
最后,我通过在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