LoginSignup
29
50

More than 5 years have passed since last update.

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

Posted at

概要

  • スキルアップのため、レシピ投稿サイトを作っていました(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を無効化する!!

  • これで無事に保存されました!!
29
50
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
29
50