質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Active Record

Active Recordは、一つのオブジェクトに対しドメインのロジックとストレージの抽象性を結合するデザインパターンです。

Q&A

1回答

6039閲覧

【Rails】 複数外部キーを持つ3つ以上のモデルから、一度にレコードを作成したい

akai

総合スコア39

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Active Record

Active Recordは、一つのオブジェクトに対しドメインのロジックとストレージの抽象性を結合するデザインパターンです。

0グッド

4クリップ

投稿2016/10/19 07:25

編集2016/12/12 12:21

###前提・実現したいこと
以下のような構成のmodelがあるとしたときに、これらを一度のsaveで同時作成したいです。

user.rb

ruby

1# id 2has_many :user_jobs, inverse_of: :user 3has_many :contacts 4accepts_nested_attributes_for :user_jobs 5accepts_nested_attributes_for :contacts

user_job.rb

ruby

1# id, user_id 2belongs_to :user 3has_one :contact 4accepts_nested_attributes_for :user 5accepts_nested_attributes_for :contact 6validates :user, presence: true # inverse_ofを利用しているのでpresenceは:user_idではなく:user

contact.rb

ruby

1# id, user_id, user_job_id, 2belongs_to :user 3belongs_to :user_job 4accepts_nested_attributes_for :user 5accepts_nested_attributes_for :user_job 6validates :user_id, :user_job_id, presence: true

###発生している問題・エラーメッセージ
最後のアソシエーションの外部キーがセットされないようで、バリデートに引っかかってしまいます。

ruby

1# 試行1 2u = User.create(contacts_attributes: [{ user_job_attributes: {} }]) 3# u.errors => contacts.user_jobs.user_id を入力してください 4 5# 試行2 6c = Contact.create(user_attributes: { user_jobs_attributes: [{}] }) 7# c.errors => user.user_jobs.user_id を入力してください

いろいろ試したのですが、paramsを整形、もしくは*_attributesやbuildなどを使用して(ApplicationRecord.transactionを書かずにRailsっぽく)、
トランザクション内でsaveする方法はないのでしょうか?

###2016-12-12追記

  • inverse_ofが必要そうなので、modelを若干修正しました。

  • 目的としましては以下のようなコードで実現できますが、こちらを「Railsの機能でもっとイイカンジに書けるのではないか」、と考えています。

ruby

1 def create 2 # user_params => { user_jobs_attributes: [{}] } 3 # viewでは@user.errorsをeachで回したいので@userのスコープをtransactionの外に 4 @user = User.new(user_params) 5 ApplicationRecord.transaction do 6 @user = User.save 7 @user.user_jobs.each do |user_job| 8 @user.update(user_jobs_attributes: [id: user_job.id, contact_attributes: { user_id: @user.id }]) 9 end 10 raise if @user.errors.present? # validationエラーがあれば例外を発生させ、rescueで拾う 11 redirect_to @user, notice: '更新に成功しました' 12 rescue 13 render :new 14 end 15 end

###補足情報(言語/FW/ツール等のバージョンなど)
Rails 5.0.0.1

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

深く考えずに一度userだけ作成
その後差分をアップデートで無理やり通してください。

ruby

1@user=User.create(id: nil,name: '氏名') 2@user.update(contacts_attributes: [{ user_job_attributes: {}])

色々悩むよりいいです

投稿2016/12/12 06:16

編集2016/12/12 08:31
moke

総合スコア2241

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

akai

2016/12/12 06:44 編集

一度作成したインスタンスのerrors情報は、updateで更新されるんですね、知りませんでした。 ですが、このままでは `user_jobs`テーブルの `user_id`カラムに値がセットされず、validationで弾かれてしまうように思います。
moke

2016/12/12 08:31

すみません、インスタンスを更新です。
moke

2016/12/12 08:34

回答を更新しておきました
akai

2016/12/12 08:43

あ、「インスタンスを更新するんだろうな」というのは編集前のコードから予想して、それを前提の返答をしてしまいました。 このコードでも「user_jobsにuser_idの値がセットされないので、validationに引っかかってしまう」と思うのですが、いかがでしょうか?
moke

2016/12/12 09:22

多分大丈夫だと思うのですが。 少なくとも私の似た環境でやってみた限り大丈夫でした。 うまくいかない場合 @user.update(contacts_attributes: [{ user_job_attributes: {user_id: @user.id}]) とか、工夫してみてください。 @user.update_atrribute(contacts_attributes: [{ user_job_attributes: {}]) とかやるとvalidationが回避できます。 使い分けてください 参考サイト http://qiita.com/tyamagu2/items/8abd93bb7ab0424cf084 「と思うのですが」 と何事にも疑問を持つのはいいことですが 一度、やってみて、できなかったらコメントをください。 こちらも、ボランティアですので
akai

2016/12/12 11:31

手元での環境再現をおろそかにしたコメント返信、申し訳ありません。 再現しましたところ、上記の私のコメント通りの結果となりました。 また、条件としまして「一度のsaveで」「ActiveRecord::Base.transaction do~を書かずに」という部分を満たしたかったです。 ちょっと質問を書き足すことにしますね、わかりづらくて申し訳ないです……。
moke

2016/12/14 04:01

まあ、そもそもaccept_nested_attributeは多段階になると非推奨、activemodelで定義した方が綺麗なコードが書けると、英語のコラムで読んだ気がします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問