概要
中級者は知ってて当然なので、初心者向けです🔰
アソシエーションで関連付けられたモデルを保存する時に、片方のレコードに外部キーが設定されているせいで、「保存処理を2回に分けなきゃ」と思ったことはないですか?(保存するまでidが確定しないので)
そんなときどうするのというお話です
※ 自分もかつて良くないコードを書いていたので、同じような初心者の参考になってもらえれば幸いです
具体例
例えば本のモデル(Book)と著者のモデル(Author)があると想定します
(book has_many authors
の関係)
Bookモデル📕
カラム | 型 | 補足 |
---|---|---|
id | integer | |
title | string |
Authorモデル
カラム | 型 | 補足 |
---|---|---|
id | integer | |
book_id | integer | 外部キー |
name | string |
このとき初心者がやりがちなのが以下の書き方
# createアクション
book = Book.new(book_params)
if book.save
author = Author.new(book_id: book.id, name: author_params[:name])
if author.save
# 保存後の処理
else
# 失敗時の処理
end
else
# 失敗時の処理
end
# book_params, author_paramsの定義は省略してます
これだと以下のようにデメリットが大きいです
- if文の階層が深くなる
- bookだけ保存されてauthorが保存されない場合が出てしまう
早期リターンやtransactionでこれらを回避することもできますが、わざわざそんな面倒なことをしなくて済む方法があるのです✨(以下)
# createアクション
book = Book.new(book_params)
author = book.build_author(author_params)
return ['保存成功時の処理'] if book.save
# 失敗時の処理
この場合book
の保存が成功した場合はauthor
の保存も保証してくれます(片方だけ保存されることはない)
当然外部キーは関連付けられて保存されます
すっきりしていて見やすく、ファットコントローラ対策にもなります😍
※ 早期リターンでリファクタもしてます
モデルの関係性が、belongs_to
とhas_many
とで書き方が変わるので注意が必要です(以下参照)
belongs_to
で関連付けられたモデルのbuild
book.build_author
has_oneでの関連付けもこちらになります
has_many
で関連付けられたモデルのbuild
author.books.build
-
1つだけ紐づくモデル
=>build_[モデル名の単数形]
-
複数紐づくモデル
=>[モデル名の複数形].build
と覚えとけば良さそうです😇
(build_複数形
にするとインスタンスが複数buildされるイメージがつくからこのように分けたんですかね🤔)