【Rails】1つの入力フォームで複数テーブルにデータを保存する方法【fields_for】
はじめに
通常form_withを使った入力フォームは、フォームに値を入力して送信ボタンを押すことで、入力値が特定のテーブルに保存されます。
すぐわかると思いますが、簡単な例としてコードと動作を載せておきます。
= form_with(model: @post, local: true) do |f|
= f.text_field :content
= f.submit "投稿"
入力内容がpostsテーブルに保存され、トップページにリダイレクトするという動作です。
もしpostsテーブルとは別で投稿内容のタグを保存できるようにしたい場合、postsテーブルに紐づいたtagsテーブルを作成し、そちらにも同時にデータを保存できるようにする必要があります。
完成イメージとテーブルのイメージとしては以下のような感じです。
これぐらいなら同一テーブルでも良さそうですが、簡単な使い方を理解するためにシンプルにしていると思ってください。
postsテーブル
Column | Type | Options |
---|---|---|
content | string | null: false |
tagsテーブル
Column | Type | Options |
---|---|---|
content | string | null: false |
post_id | integer | foreign_key |
この操作では一つの入力フォームからpostsテーブルとtagsテーブルにそれぞれ保存しています。
どうやって実装すればよいでしょうか?順番にみていきましょう!
tagsテーブルの用意
Tagモデルとテーブルを作っていきます。
$ rails g model tag
class CreateTags < ActiveRecord::Migration[5.2]
def change
create_table :tags do |t|
t.string :content, null: false # 追記
t.references :post, null: false, foreign_key: true # 追記
t.timestamps
end
end
end
$ rails db:migrate
モデル(Post, Tag)
モデルのファイルに追加します。
class Post < ApplicationRecord
validates :content, presence: true # 空のデータをはじくバリデーション
has_many :tags, dependent: :destroy # アソシエーション + postレコードを削除したときに紐づいたtagを同時に削除
accepts_nested_attributes_for :tags, allow_destroy: true # fields_for(後述)に必要
end
class Tag < ApplicationRecord
validates :content, presence: true # 空のデータをはじくバリデーション
belongs_to :post # アソシエーション
end
これでモデルの準備はできました。
フォーム
続いてフォームを編集しましょう。
= form_with(model: @post, local: true) do |f| # postモデルのフォーム作成メソッド
.post-area
.post-area__title
投稿内容
.post-area__form
= f.text_field :content # postモデルのフォームは通常どおり
= f.fields_for :tags do |tag| # 別のモデルのフォームはfield_forメソッドを使う
.tag-area
.tag-area__title
タグ
.tag-area__form
= tag.text_field :content
= f.submit "投稿"
fields_forメソッドを使うことで、Postモデルに関連したモデルのフィールドを作成できるようになります。
関連したモデルというのは上で出てきたaccepts_nested_attributes_for
を記述したモデルのことです。今回はTagモデルが該当します。
コントローラ
続いてコントローラを編集しましょう!
class PostsController < ApplicationController
# index, edit, update, destroyは省略してます
def new
@post = Post.new
@tag = @post.tags.new
end
def create
@post = Post.new(post_params)
if @post.save
redirect_to root_path
else
render "new"
end
end
private
def post_params
params.require(:post).permit(:content, tags_attributes: [:content, :_destroy, :id])
end
end
ストロングパラメータ(post_params)内でのtagの書き方が少し特殊になります。
テーブル名_attributes: [:カラム名, :_destroy, :id]
という形です。
createアクションのみであれば, :_destroy, :id
は不要ですが、これを書くことで更新や削除もいい感じにやってくれます。
これで最初に載せたようなフォームの挙動が再現できるかと思います。
最後に
今回はタグの入力は1つだけでしたが、実際はタグを複数入力できたほうが使いやすいかと思います。JavaScriptを利用すれば、フォームを自由に追加して複数のタグを登録できるのですが、やや複雑なのでそれに関しては別の記事にしたいと思います。
field_forの使い方がなんとなく理解できれば御の字です。
ご意見、ご質問があればコメントよろしくお願いします!
Author And Source
この問題について(【Rails】1つの入力フォームで複数テーブルにデータを保存する方法【fields_for】), 我々は、より多くの情報をここで見つけました https://qiita.com/koki_73/items/bc4ca80ab43e84d9704f著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .