Posted at

一つのform_forで複数のテーブルに保存!!

More than 1 year has passed since last update.


概要


  • スキルアップのため、レシピ投稿サイトを作っていました(cookpadのようなもの)。

  • 一つのレシピにつき、複数の写真を投稿できるようにしたかった。

  • 以下の記事を参考に、form_for + fields_forで、recipeレコードが保存されると、それに関連したimageレコードも保存されるようにした。

複数のレコードを作成する。modelの関係性によって異なるform_for / fields_forの使い方

Rails 複数の子レコードの作成・更新を自在に扱う (accepts_nested_attributes_for)

Railsで階層化された複数モデルに対応するフォームの作り方


上記サイトのコピーで、書いたコード


  • コントローラー


recipes_controller.rb

class RecipesController < ApplicationController

def new
@recipe = Recipe.new
@recipe.images.build
end

def create
recipe = current_user.recipes.new(recipe_params)
recipe.save
redirect_to root_path
end

private

def recipe_params
params.require(:recipe).permit(:name, images_attributes: [:image])
end

end



  • ビュー


new.html.erb

<%= form_for @recipe do |f|  %>

<%= f.text_field :name %>
<%= f.fields_for :images do |i| %>
<%= i.file_field :image %>
<% end %>
<%= f.submit "Save",name:"commit" %>
<% end %>



  • imageモデル


image.rb

class Image < ApplicationRecord

belongs_to :recipe
end


  • recipeモデル


recipe.rb

class Recipe < ApplicationRecord

belongs_to :user
has_many :images
accepts_nested_attributes_for :images
end


しかし、これだと保存されない!!


  • 結論から言うと、imageモデルの記述を、belongs_to :recipe,optional: trueにすると無事に保存されました!!

  • なぜ、optional: trueがないと、ダメかと言うと、rails5から、belongs_toに対して、required:trueがデフォルトで設定されているからみたいです。


required:trueとは


  • (私の理解が正しければ)値がnilだと保存されないよ!というものです。

  • つまり、imageモデルにはbelongs_to :recipeしか書いてなくとも、実際はbelongs_to :recipe,required:trueとなっているということです。


rails5はデフォルトでは、外部キー(hoge_id)のnilは許させない!!


  • DBに保存されるまでは、idはnilなので、つまり、imageモデルでの時点では、recipe_id(imageレコードの外部キー)はnilなので、
    required:trueのバリデーションに引っかかり、保存されなかったということみたいです!!


optional: trueはrequired:trueを無効化する!!


  • これで無事に保存されました!!