【问题标题】:Rails HABTM after_add callback fires before saving primary objectRails HABTM after_add 回调在保存主要对象之前触发
【发布时间】:2016-11-17 21:08:20
【问题描述】:

我有两个具有 HABTM 关系的 ActiveRecord 模型。 当我通过允许通过选中复选框添加区域的表单添加 AccessUnit 时,我得到一个异常,即 AccessUnitUpdaterJob 无法入队,因为传递的访问单元无法序列化(由于缺少标识符) .在主对象上手动调用 save 时,问题已解决,但当然这是一种解决方法,而不是正确的修复方法。

TLDR;似乎在保存主对象之前触发了 after_add 回调。我实际上不确定这是 Rails 中的错误还是预期的行为。我正在使用 Rails 5。

我遇到的确切错误是:

ActiveJob::SerializationError in AccessUnitsController#create

Unable to serialize AccessUnit without an id. (Maybe you forgot to call save?)

这里有一些代码,您可以查看问题的上下文:

class AccessUnit < ApplicationRecord
  has_and_belongs_to_many :zones, after_add: :schedule_access_unit_update_after_zone_added_or_removed, after_remove: :schedule_access_unit_update_after_zone_added_or_removed

  def schedule_access_unit_update_after_zone_added_or_removed(zone)
    # self.save adding this line solves it but isn't a proper solution
    puts "Access unit #{name} added or removed to zone #{zone.name}"

    # error is thrown on this line
    AccessUnitUpdaterJob.perform_later self
  end
end

class Zone < ApplicationRecord
  has_and_belongs_to_many :access_units
end

【问题讨论】:

标签: ruby-on-rails rails-activerecord ruby-on-rails-5 has-and-belongs-to-many


【解决方案1】:

在我看来,这不是错误。每件事都按预期工作。在保存此图之前,您可以创建一个复杂的对象图。在此创建阶段,您可以将对象添加到关联中。这是您要触发此回调的时间点,因为它显示的是 after_add 而不是 after_save。

例如:

@post.tags.build name: "ruby" # <= now you add the objects
@post.tags.build name: "rails" # <= now you add the objects
@post.save! # <= now it is to late, for this callback, you added already multiple objects

也许使用before_add 回调更有意义:

class Post
   has_many :tags, before_add: :check_state

   def check_state(_tag)
     if self.published?
        raise CantAddFurthorTags, "Can't add tags to a published Post"
     end
   end
end

@post = Post.new
@post.tags.build name: "ruby" 
@post.published = true
@post.tags.build name: "rails" # <= you wan't to fire the before_add callback now, to know that you can't add this new object 
@post.save! # <= and not here, where you can't determine which object caused the error

您可以在“The Rails 4 Way”一书中阅读有关这些回调的一些信息

在您的情况下,您必须重新考虑您的逻辑。也许您可以使用after_savecallback。 我的 2 美分:您考虑从回调切换到服务对象。 回调并非没有代价。它们并不总是易于调试和测试。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    • 2016-11-20
    相关资源
    最近更新 更多