【问题标题】:Detect relation changes on polymorphic association检测多态关联的关系变化
【发布时间】:2017-04-26 20:33:10
【问题描述】:

我有 2 个通过多态关联链接的模型

class MyModel < ActiveRecord::Base
  has_many :taggings, :as => :taggable
  has_many :tags, :through => :taggings

  def tags=(ids)
    self.tags.delete_all
    self.tags << Tag.where(id: ids)
  end
end

class Tagging < ActiveRecord::Base
  include PublishablePolymorphicRelationship
  belongs_to :tag
  belongs_to :taggable, :polymorphic => true
end


class Tag < ActiveRecord::Base
  has_many :taggings
  has_many :my_models, :through => :taggings, :source => :taggable, :source_type => 'MyModel'
end

tag1 = Tag.create!(...)
tag2 = Tag.create!(...)
my_model = MyModel.create!(...)

my_model.update!(tags: [tag1.id])

我创建了一个实现 after_update 挂钩的关注点,以便我可以在消息队列上发布更改

但是,当调用钩子时,更改哈希为空。以及关系

module PublishablePolymorphicRelationship
  extend ActiveSupport::Concern
  included do
    after_update    :publish_update

    def publish_update
      model = self.taggable
      puts model.changes
      puts self.changes
      ... # do some message queue publish code
    end
  end

结束 这将返回

{}
{}

有没有办法可以捕捉到多态关联的变化。 理想情况下,我不会在关注点中直接引用tags 模型,因为我希望这个关注点可用于其他模型。不过,我愿意使用关注点在模型中添加一些配置。

跟进问题:这样做是否正确?我很惊讶更新挂钩首先被调用。也许我应该对创建或删除挂钩采取行动?我愿意接受建议。

【问题讨论】:

  • 首先摆脱 hacky MyModel#tags= setter。通过使用 rails 为任何 has_many 关联创建的 tags_ids= 设置器,已经有更好的内置方法来执行此操作。它也可以与复选框助手一起使用。
  • 另外,为了您的工作,您需要将after_update :publish_update 放在included do ... end 块中。回调和关联是在模型的类定义中定义的。但我真的不明白你为什么要使用关注点,因为它似乎不太可重用。
  • 为了简化示例,我在实践中使用self.taggable 对模型进行硬编码,我使用类方法来设置多态关系键并使用self.send(_polymorphic_key) 这有意义吗?您认为这会提高可重用性吗?
  • 是的,这使它完全不同。您可能需要阅读 ActiveSupport::Concern 的文档,因为您需要记住,需要在类的上下文中评估的代码需要在模块包含在类中时运行 - 而不是在模块定义中。
  • 这是一个很好的提醒(可能会为未来的读者服务)。幸运的是,我知道这一点。

标签: ruby-on-rails ruby-on-rails-4 activerecord polymorphic-associations


【解决方案1】:

它永远不会像你想象的那样工作 - taggings 只是一个连接模型。仅当您向项目添加/删除标签时,才会真正间接地插入/删除行。当这种情况发生时,关联的两端都不会发生任何变化。

因此,除非您实际手动更新标记和关联的任一端,否则publish_update 将返回 en 空哈希。

如果您想创建一个可重用组件,在创建/销毁 m2m 关联时通知您,您可以这样做:

module Trackable

  included do
    after_create :publish_create!
    after_destroy :publish_destroy!
  end

  def publish_create!
    puts "#{ taxonomy.name } was added to #{item_name.singular} #{ item.id }"
  end

  def publish_destroy!
    puts "#{ taxonomy.name } was removed from #{item_name.singular} #{ item.id }"
  end

  def taxonomy_name
    @taxonomy_name || = taxonomy.class.model_name
  end

  def item_name
    @item_name || = item.class.model_name
  end
end

class Tagging < ActiveRecord::Base
  include PublishablePolymorphicRelationship
  belongs_to :tag
  belongs_to :taggable, polymorphic: true

  alias_attribute :item, :taggable
  alias_attribute :taxonomy, :tag
end

class Categorization < ActiveRecord::Base
  include PublishablePolymorphicRelationship
  belongs_to :category
  belongs_to :item, polymorphic: true

  alias_attribute :item, :taggable
  alias_attribute :taxonomy, :tag
end

否则,您需要将跟踪回调应用到您对更改感兴趣的实际类。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2012-05-22
  • 2015-06-22
  • 1970-01-01
  • 2014-01-09
  • 1970-01-01
  • 2019-02-01
  • 1970-01-01
  • 2020-04-12
相关资源
最近更新 更多