簡體   English   中英

使用單個 form_with 在 Rails 中創建和編輯嵌套資源

[英]Use a single form_with to create and edit nested resources in Rails

背景

在我的應用程序內部,一個系列由許多書籍組成。 系列的“顯示”頁面允許用戶查看系列中的所有書籍並使用表單向系列添加新書籍。

Show頁面上列出的每本書都有一個指向該書的Edit頁面的鏈接。 編輯頁面包含用於最初添加書籍的相同表單 編輯書籍時,表單應自動填充書籍現有信息。

如何配置我的form_with標簽,以便它既可以創建新書又可以編輯現有書(自動填寫編輯表單)? 我嘗試了以下配置,但它們要么破壞了編輯頁面,要么破壞了顯示頁面:

  1. <%= form_with(model: [ @series, @series.books.build ], local: true) do |form| %>
    • 打破書編輯頁面
    • 錯誤:沒有錯誤,但表單不會自動填充數據
  2. <%= form_with(model: @book, url: series_book_path, local: true) do |form| %>
    • 休息系列 顯示頁面
    • 錯誤: No route matches {:action=>"show", :controller=>"books", :id=>"6"}, missing required keys: [series_id]
  3. <%= form_with(model: [:series, @book], local: true) do |form| %>
    • 休息系列 顯示頁面
    • 錯誤: Undefined method 'model_name' for nil:NilClass
  4. <%= form_with(model: [@series, @series.books.find(@book.id)], local: true) do |form| %>
    • 休息系列 顯示頁面
    • 錯誤: undefined method 'id' for nil:NilClass
  5. <%= form_with(model: @book, url: [@series, @book], local: true) do |form| %>
    • 在系列顯示頁面上提交新書時中斷
    • 錯誤: No route matches [POST] "/series/6"

我咨詢過的資源:

現有代碼

下面是相關代碼的精簡部分,以及指向它們在我當前 GitHub 存儲庫中的位置的鏈接。

配置/路由.rb

resources :series do
  resources :books
end

應用程序/模型/ book.rb

class Book < ApplicationRecord
  belongs_to :series
end

應用程序/模型/ series.rb

class Series < ApplicationRecord
  has_many :books, dependent: :destroy
end

數據庫/模式.rb

create_table "books", force: :cascade do |t|
  t.integer "series_number"
  t.integer "year_published"
  t.integer "series_id"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
  t.index ["series_id"], name: "index_books_on_series_id"
end

create_table "series", force: :cascade do |t|
  t.string "title"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end

應用程序/視圖/系列/ show.html.erb

<%= render @series.books %>
<%= render 'books/form' %>

應用程序/視圖/書籍/_book.html.erb

<%= link_to 'Edit', edit_series_book_path(book.series, book) %>

app/views/books/ edit.html.erb

<%= render 'form' %>

應用程序/視圖/書籍/_form.html.erb

<%= form_with(model: @book, url: [@series, @book], local: true) do |form| %>
  <%= form.label :series_number %>
  <%= form.number_field :series_number %>

  <%= form.label :year_published %>
  <%= form.number_field :year_published %>
<% end %>

應用程序/控制器/books_controller.rb

class BooksController < ApplicationController
  def index
    @books = Book.all
  end

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

  def new
    @book = Book.new
  end

  def edit
    @series = Series.find(params[:series_id])
    @book = @series.books.find(params[:id])
  end

  def create
    @series = Series.find(params[:series_id])
    @book = @series.books.create(book_params)
    redirect_to series_path(@series)
  end

  def destroy
    @series = Series.find(params[:series_id])
    @book = @series.books.find(params[:id])
    @book.destroy
    redirect_to series_path(@series)
  end

  private
    def book_params
      params.require(:book).permit(:year_published, :series_number)
    end
end

路線

          Prefix Verb   URI Pattern                                 Controller#Action
        articles GET    /articles(.:format)                         articles#index
                 POST   /articles(.:format)                         articles#create
     new_article GET    /articles/new(.:format)                     articles#new
    edit_article GET    /articles/:id/edit(.:format)                articles#edit
         article GET    /articles/:id(.:format)                     articles#show
                 PATCH  /articles/:id(.:format)                     articles#update
                 PUT    /articles/:id(.:format)                     articles#update
                 DELETE /articles/:id(.:format)                     articles#destroy
    series_books GET    /series/:series_id/books(.:format)          books#index
                 POST   /series/:series_id/books(.:format)          books#create
 new_series_book GET    /series/:series_id/books/new(.:format)      books#new
edit_series_book GET    /series/:series_id/books/:id/edit(.:format) books#edit
     series_book GET    /series/:series_id/books/:id(.:format)      books#show
                 PATCH  /series/:series_id/books/:id(.:format)      books#update
                 PUT    /series/:series_id/books/:id(.:format)      books#update
                 DELETE /series/:series_id/books/:id(.:format)      books#destroy
    series_index GET    /series(.:format)                           series#index
                 POST   /series(.:format)                           series#create
      new_series GET    /series/new(.:format)                       series#new
     edit_series GET    /series/:id/edit(.:format)                  series#edit
          series GET    /series/:id(.:format)                       series#show
                 PATCH  /series/:id(.:format)                       series#update
                 PUT    /series/:id(.:format)                       series#update
                 DELETE /series/:id(.:format)                       series#destroy

您可以將數組傳遞給表單以處理嵌套和“淺”路由:

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

<% end %>

Rails 壓縮數組(刪除 nil 值),因此如果@series為 nil,表單將回book_url(@book)books_url 但是,您需要從控制器正確處理設置@series@book

class SeriesController < ApplicationController
  def show
    @series = Series.find(params[:id])
    @book = @series.books.new # used by the form
  end
end

您可以使用局部變量在視圖中處理此問題:

# app/views/books/_form.html.erb
<%= form_with(model: model, local: true) do |form| %>

<% end %>

# app/views/books/edit.html.erb
<%= render 'form', locals: { model: [@series, @book] } %>

# app/views/series/show.html.erb
<%= render 'books/form', locals: { model: [@series, @series.book.new] } %>

你也可以在你的路由中使用shallow: true選項來避免嵌套成員路由(顯示、編輯、更新、銷毀):

resources :series do
  resources :books, shallow: true
end

這將讓你只做:

# app/views/books/edit.html.erb
<%= render 'form', model: @book %>

# app/views/books/_book.html.erb
<%= link_to 'Edit', edit_book_path(book) %>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM