Railsからはじめるプログラミング日記

駆け出しプログラマー(主にRuby on Rails)の業務で役立ったコードをメモしていくブログです。自分だけでなく誰かの役に立てれば本望です。

【Rails】1つのフォームタグで紐付いたテーブルの項目も登録したい場合

例えば「企業(company)」テーブルと「事業所(office)」テーブルがあるとします。

企業と事務所の関係は、企業が複数の事業所を持っているということで、1対多の関係です。

モデルの紐付けと設定

親のcompanyに「accepts_nested_attributes_for :offices」の1文を記載する。

【models/company.rb】

class Company < ApplicationRecord
  has_many :offices, inverse_of: :company
  accepts_nested_attributes_for :offices
end

【models/office.rb】

class Office < ApplicationRecord
  belongs_to :company, inverse_of: :offices
end

inverse_ofはcompanyもofficeも新規で作成する場合、もとにするcompanyのidが見つからないというエラーを起こすので、それを防ぐために記載する

@companyの定義と関連テーブルのbuild

@companyを定義し、紐づく@officesをbuildします

【controllers/company_controller.rb】

class CompaniesController < ApplicationController
  def new
    @company = Company.new
    @office = @company.offices.build
  end
end

追加でparamsの受け取りも定義してやります。

class CompaniesController < ApplicationController
  def new
    @company = Company.new
    @office = @company.offices.build
  end

  private
    def company_params
      params.require(:company).permit( :name, :url, offices_attributes: [:id, :company_id, :name, :postal, :prefecture, :address, :building, :tel, :fax, :remark] )
    end
end

最後にviewのフォームを設定

@companyの項目はいつも通りに、buildしたofficeの項目について「fields_for」で入力項目を出します。
※controllerでbuildしないと入力項目が表示されません 【views/companies/_form.html.erb】

<%= form_with(model: @company) do |form| %>
  <table>
    <tr>
      <th rowspan="3"><%= form.label f(Company, :name) %></th>
      <td class="sub"><%=f Company, :name %></td>
      <td><%= form.text_field :name %></td>
    </tr>
    <tr>
      <th><%= form.label f(Company, :url) %></th>
      <td colspan="2"><%= form.text_field :url %></td>
    </tr>

    <%= form.fields_for :offices do |office| %>
      <tr>
        <th><%= office.label :postal %></th>
        <td colspan="2">
          <%= office.text_field :postal %>
        </td>
      </tr>
      <tr>
        <th><%= office.label :prefecture %></th>
        <td colspan="2">
          <%= office.select :prefecture, PrefectureList %>
        </td>
      </tr>
      <tr>
        <th><%= office.label :address %></th>
        <td colspan="2">
          <%= office.text_field :address %>
        </td>
      </tr>
      <tr>
        <th><%= office.label :building %></th>
        <td colspan="2">
          <%= office.text_field :building %>
        </td>
      </tr>
      <tr>
        <th><%= office.label :tel %></th>
        <td colspan="2">
          <%= office.text_field :tel %>
        </td>
      </tr>
      <tr>
        <th><%= office.label :fax %></th>
        <td colspan="2">
          <%= office.text_field :fax %>
        </td>
      </tr>
      <tr>
        <th><%= office.label :remark %></th>
        <td colspan="2">
          <%= office.text_area :remark %>
        </td>
      </tr>
    <% end %>
  </table>
  <%= form.submit %>
<% end %>

こんな感じでフォームを分けなくても一気に登録することができます。

筆者オススメ技術書