Rails: "has_many", "blongs_to"でリレーショナルなテーブル関係を設定する_コントローラ、ビュー実装

前回、以下にて"has_many", "blongs_to"でリレーショナルなテーブル関係を設定したので実際に使えるようにコントローラとビューへ実装する.
teki-com.hateblo.jp


参考サイト
has_manyとbelongs_toについて。モデルの関連付けされたformの作り方 - Qiita
第11章ユーザーのマイクロポスト - Railsチュートリアル
html - No route matches missing required keys: [:id] - Stack Overflow
Rails のルーティング - Rails ガイド
RailsのScaffoldでネストしたResourceを作る - sometimes I laugh
ネストした form_with のリダイレクト先がエラーになってしまう - Qiita

ルーティングをネスト構造へ変更

以下でAuthorの下にBookを入れる.
[config/routes.rb]

  resources :authors do
    resources :books
  end

ルーティングをネスト構造にすることで、以下のようにpathが自動的に割り当てられる.
f:id:Kurorera:20190525212130p:plain




Authorの設定

基本的に何もする必要なし。だけどBookの一覧表示へのリンクのみ作成しておく.

[app/views/authors/show.html.erb]

<%= link_to 'Book一覧', author_books_path(@author) %> 

Book側の設定

ルーティング(path)が変わっているのでそれに合わせて変更する必要あり.

indexアクション
[app/controller/books_controller.rb]
FROM

  # GET /books
  def index
    @books = Book.all
  end

TO

  # GET /authors/:author_id/books
  def index
    @author = Author.find(params[:author_id])
    @books = Author.find(params[:author_id]).books
  end

ビューを以下のようにパスを変更する.
[app/views/authors/index.html.erb]

  <td><%= link_to 'Show', author_book_path(@author,book) %></td>
  <td><%= link_to 'Edit', edit_author_book_path(@author,book) %></td>
  <td><%= link_to 'Destroy', author_book_path(@author,book), method: :delete, data: { confirm: 'Are you sure?' } %></td>

showアクション
コントローラ

  # GET  /authors/:author_id/books/1
  def show
    @author = Author.find(params[:author_id])
    @books = Author.find(params[:author_id]).books
  end

ビュー

<%= link_to 'Edit', edit_author_book_path(@author,@book) %> 
<%= link_to 'Back', author_books_path(@author) %>

共通処理の"_form.html.erb"の一行目の処理にauthorを追加する.
[app/view/books/_form.html.erb]

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

newおよびcreateアクション
コントローラ
[app/controllers/books_controller.rb]

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

  # POST /authors/:author_id/books
  def create
    @author = Author.find(params[:author_id])
    @book = Author.find(params[:author_id]).books.new(book_params)
    
    respond_to do |format|
      if @book.save
        format.html { redirect_to [@author,@book], notice: 'Book was successfully created.' }
        ...
      else
       ...
      end
    end
  end

ビュー
[app/views/books/new.html.erb]

<%= render 'form', author: @author, book: @book %>

<%= link_to 'Back', author_books_path(@author) %>


もう一度"_form.html.erb"に移動し、今度は16行目をの"form.text_field :author_id"とすることで初期値にauthor_idとしておく

<%= form.text_field :author_id, id: :book_author %>

editおよびupdateアクション
コントローラ

  # GET /authors/:author_id/books/1/edit
  def edit
    @author = Author.find(params[:author_id])
    @books = Author.find(params[:author_id]).books
  end

  # PATCH/PUT authors/:author_id/books/1
  def update
     @author = Author.find(params[:author_id])

      if @book.update(book_params)
        format.html { redirect_to [@author,@book], notice: 'Book was successfully updated.' }
         ...
      else
        ...
      end
    end
  end

ビュー

<%= render 'form', author: @author, book: @book %>

<%= link_to 'Edit', edit_author_book_path(@author,@book) %>
<%= link_to 'Back', author_books_path(@author) %>

updateはビューを持っていないので省略


Destroyアクション
コントローラ
[app/controllers/books_controller.rb]

  # DELETE authors/:author_id/books/1
  def destroy
       ...
      format.html { redirect_to author_books_url, notice: 'Book was successfully destroyed.' }
      ...
    end
  end

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

Destroyはビューを持っていないので省略

以上.すごく荒削りにしか開催していないのであまり参考にしないでください.
いずれわかりやすく書き直します.今はメモ程度.