フォームオブジェクトで fields_for を使う:editの場合

フォームオブジェクトで fields_for を使う:newの場合の続き。

edit.html.erbの準備

new.html.erbと共通部分を _form.html.erb へ抜き出す。

new.html.erbは以下のとおり。なお、最後の #editアクションへのリンクの中のidは適当に決めている(今回はidを使わないため)。また、form_data をパーシャルのlocals属性を使って、_form.html.erbへ渡している。

<%= bootstrap_form_for(@book_list, :url => {controller: :input_forms, action: :create}) do | form_data |-%>

  <%= render partial: 'form', locals: {form_data: form_data} %>

<% end -%>
<hr>
<%= link_to 'Edit', edit_input_form_path(1) -%>

edit.html.erb は以下のとおり。メソッドとして patch を指定する必要がある。

<%= bootstrap_form_for(@book_list, url: {controller: :input_forms, action: :update}, method: :patch) do | form_data |-%>

  <%= render partial: 'form', locals: {form_data: form_data} %>

<% end -%>

_form.html.erb は以下のとおり。

<%= form_data.fields_for :books do | field_data | -%>
  <%= field_data.text_field :title %>
  <%= field_data.text_field :author %>
  <%= field_data.number_field :price %>
  <%= field_data.text_field :isbn %>
<% end -%>
<%= form_data.submit %>

edit.html.erbの方では、隠しフィールドとして、Bookオブジェクトのidを送る inputタグが生成される。

コントローラーの変更

InputFormsControllerに#edit アクション、 #update アクションを追加し、Strong Parameter用のメソッドに :id を追加する。

  def edit
    @book_list = BookInputForm.new
    @book_list.load  #新たにインスタントメソッドを用意する
  end

  def update
    #createアクションと同じだが、内部でupdateを読んでいるのでsaveしない。
    @book_list = BookInputForm.new(book_input_params) 
    redirect_to books_path  
  end

  private
  def book_input_params  # :id を新たに付け加える
    params.require(:book_input_form).permit(books_attributes: [:id, :title, :author, :price, :isbn])
  end

フォームオブジェクトの変更

BookInputFormに、既に格納済みのBookオブジェクトを読み込む loadメソッドを追加する。

  def load
    @books = Book.all.to_a
  end

また、#updateアクションにて、#createと同じ書き方をできるようにbooks_attributesを変更する。

  def books_attributes=(attributes)
    @books ||= []
    attributes.each do | i, book_params|
      if book_params.key?(:id) # :idキーが追加されているならば、更新である
        book = Book.find(book_params[:id])
        book.update(book_params) unless book.blank?
      else # :idキーがなければ新規作成
        @books.push(Book.new(book_params))
      end
    end
  end

これで、既に保存済みのBookオブジェクトもまとめて編集できる。