1
1

More than 5 years have passed since last update.

【rails】入れ子になったformの作り方(rspecも)

Posted at

railsで中間テーブルも含んだformをつくるのになかなか苦労したので記事にしました。
誰かの役に立てば幸いです。

やりたいこと

  • 母のデータはすでに登録してある
  • 父を登録するときに子供の情報も同時に登録する
  • そのときに母のデータも関連づけて保存

model

father.rb
has_many :children, dependent: :destroy
has_many :mothers, through: :children
accepts_nested_attributes_for :children, allow_destroy: true
mother.rb
has_many :children, dependent: :destroy
has_many :fathers, through: :children
child.rb
belongs_to :father
belongs_to :mother

controller

father_controller.rb
private
  def father_params
    params.require(:father).permit(:name, :children_attributes: [:id, :mother_id, :age, :_destroy])
  end

view

new.html.haml
= simple_form_for @father do |f|
  = f.input :name, place_holder: "名前", label: false
  - @mothers.each  do |mother|
    = f.simple_fields_for :children, mother.children.build do |tif| # 母と紐付け
      = tif.input :age, place_holder: "子供の年齢", label: false
      = tif.input :mother_id, as: :hidden, value: mother.id # ここで母親のidを子に持たせる
  = f.submit "登録"

これで父と母、両方の情報を持った子が登録できます。

RSpec

テストでの情報の作り方に一番苦労した…
なぜかというと、上のnewの画面では登録ボタン→確認画面→同意ボタン→登録という流れを取っていました。
つまり、事前にデータを用意せず、テストの中で情報を登録させる必要がありました。
以下、テストコードになります。

children_spec.rb
require 'rails_helper'

feature '親子情報の登録' do
  context '親子情報が有効な場合' do
    let!(:mother) { create(:mother, name: "花子") }
    let!(:father){ Father.new(name: "太郎") } # この時点ではまだcreateさせない

    before { visit (登録画面のurl) }

    scenario '登録できること' do
      father.children.build(mother: mother, father: father, age: 1) # ここで子供の情報をbuildさせ
      father.save # ここで同時に保存

      # 以降保存できていることの処理
    end
  end
end

肝はデータをつくるときにcreateでなくnew→saveの流れを取ること。
ここでは同時保存の流れを取っているため、createさせてしまうと子情報を持たないfatherが作られてしまい、いくら子をbuildさせても同時保存されず、fatherがnilになってしまう。

複雑に絡んだテーブルだったためなかなか時間を割いたが、冷静に考えれば単純なことだった…

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1