

以下のようなモデル構造で、下記処理を実行します。

[code]

    tweet = Tweet.create
    user = User.new
    user.likes.build(tweet_id: tweet.id)
    user.save
    
[/code]

すると"Likes is invalid"となり、ロールバックされます。  
build時にuser_idがnilなので、

[code]

    validates :user_id, presence: true
    
[/code]

に引っかかっているように思います。

モデル、DB構造を変えずに、UserとLikeを同時保存するにはどのような処理が有効でしょうか？

* * *

### モデル構造

Userモデル

[code]

      has_many :likes
      has_many :tweets, through: :likes
    end
    
[/code]

Tweetモデル

[code]

    class Tweet < ApplicationRecord
      has_many :likes
      has_many :users, through: :likes
    end
    
[/code]

Likeモデル（中間テーブル）

[code]

    class Like < ApplicationRecord
      belongs_to :user
      belongs_to :tweet
      validates :user_id, presence: true
      validates :tweet_id, presence: true
    end
    
[/code]

DB

[code]

    create_table "likes", force: :cascade do |t|
      t.integer "user_id"
      t.integer "tweet_id"
      t.datetime "created_at", precision: 6, null: false
      t.datetime "updated_at", precision: 6, null: false
    end
    create_table "tweets", force: :cascade do |t|
      t.string "context"
      t.datetime "created_at", precision: 6, null: false
      t.datetime "updated_at", precision: 6, null: false
    end
    create_table "users", force: :cascade do |t|
      t.string "name"
      t.datetime "created_at", precision: 6, null: false
      t.datetime "updated_at", precision: 6, null: false
    end
    
[/code]


CC BY-SA 4.0
2021-07-18T09:44:34.117
78271
2023-01-05T02:06:15.813
2021-07-18T11:21:58.353
3060
47342
question
ruby-on-rails ruby
親子関係にあるモデルを同時保存すると、validates: user_id, presence: trueによってロールバックされます。

[code]

    tweet = Tweet.create
    User.transaction do
      user = User.create!
      user.likes.create!(tweet_id: tweet.id)
    end
    
[/code]

のようにすればバリデーションにひっかからずに作成することが可能です。ここでのポイントは`transaction`メソッドで、これにより別々にモデルを作成・保存してもどちらかが保存に失敗すれば`User`と`Like`はどちらも保存されません。これで実質的な「同時保存」の条件は満たしていると思われます。  
また、`transaction`内部で`create!`を使っているのは、このメソッドが保存失敗時に例外を発生させそれがトランザクションを巻き戻させるためです。`create`では例外が発生せずトランザクションが巻き戻らない点にご注意ください。


CC BY-SA 4.0
2021-07-18T10:25:17.597
78273
2021-07-18T10:25:17.597
442
78271
answer