0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

クイズ:なぜバリデーションエラーになるでしょう

Posted at

要約

  • railsのcallbackで中間テーブルを生成する方法をミスるとvalidationエラーになるアンチパターン

詳細

  • モデル構成
class User < ApplicationRecord
  has_many :notification_settings, dependent: :destroy
  has_many :notifications, through: :notification_settings, dependent: :destroy
  after_create :create_default_notifications
end

class NotificationSetting < ApplicationRecord
  belongs_to :user
  belongs_to :notification

  validates :user_id,  uniqueness: { scope: [:notification_id] }
end

class Notification < ApplicationRecord
  has_many :notification_settings, dependent: :destroy
  has_many :users, through: :notification_settings, dependent: :destroy
end

とかで、ユーザに通知設定が複数ひもづいている状態で、ユーザが作成されたタイミングでデフォルトの通知設定を作りたくてcreate_default_notificationsの中で

def create_default_notifications
  self.notifications = Notification.all
end

てやっていると一見OKっぽいんだけど、validates :user_id, uniqueness: { scope: [:notification_id] } で引っかかってvalildationエラーになる。

理由


self.notifications = Notification.all

が評価されたタイミングでNotificationSettingにinsertが発行されてしまって、
その後autosaveも動くので、結果2回createされてしまってuniqueじゃなくなってエラーになる。
has_manyにassignすると即insertされるというのがわかりにくかったという問題。
=はsaveされないという思い込みでした。

修正

丁寧に1件1件buildする


Notification.all.each do |notification|
  self.notification_settings.build(notification: notification)
end
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?