如何通过关联检测has_many中的更改?

时间:2019-12-20 11:07:45

标签: ruby-on-rails activerecord rails-activerecord has-many-through ruby-on-rails-6

我有以下型号。

class Company < ApplicationRecord
  has_many :company_users
  has_many :users, :through => :company_users

  after_update :do_something

  private

  def do_something
    # check if users of the company have been updated here
  end
end

class User < ApplicationRecord
  has_many :company_users
  has_many :companies, :through => :company_users
end

class CompanyUser < ApplicationRecord
  belongs_to :company
  belongs_to :user
end

然后我将这些用作种子:

Company.create :name => 'Company 1'
User.create [{:name => 'User1'}, {:name => 'User2'}, {:name => 'User3'}, {:name => 'User4'}]

假设我要更新Company 1用户,我将执行以下操作:

Company.first.update :users => [User.first, User.second]

这将按预期运行,并将在CompanyUser模型上创建2条新记录。

但是,如果我想再次更新怎么办?就像运行以下命令一样:

Company.first.update :users => [User.third, User.fourth]

这将销毁前2条记录,并在CompanyUser模型上创建另外2条记录。

问题是我在技术上{strong>更新了 模型,因此如何在Company模型上使用after_update方法检测到这些变化?

但是,更新属性就可以了:

Company

我如何也可以在关联上使用它?

到目前为止,我已经尝试了以下方法,但无济于事:

3 个答案:

答案 0 :(得分:0)

我觉得您在问一个错误的问题,因为您必须在不破坏当前关联的情况下更新您的关联。如您所说:

This will destroy the first 2 records and will create another 2 records on CompanyUser model.

知道我会建议您尝试以下代码:

Company.first.users << User.third

这样,您将不会覆盖当前关联。 如果您想一次添加多条记录,请尝试用[]或()将它们包装起来,不确定是否要使用哪一条。

您可以在这里找到文档:https://guides.rubyonrails.org/association_basics.html#has-many-association-reference

希望这会有所帮助。

编辑:

好吧,我认为这不是你真正的问题。

也许有2种解决方案:

#1观察者

我的工作是您的联接表上的观察者,它负责每次更改CompanyUser时“ ping”您的Company模型。

gem rails-observers

在此观察者内部调用服务,或者您喜欢的任何事情都将使用您想要的值进行操作

class CompanyUserObserver < ActiveRecord::Observer

  def after_save(company_user)
    user = company_user.user
    company = company_user.company
    ...do what you want
  end

  def before_destroy(company_user)
    ...do what you want
  end
end

您可以根据需要使用多个回调。

#2保留记录

事实证明您需要保留记录。也许您应该考虑使用 PaperTrail Audited 之类的宝石来跟踪您的更改。

很抱歉造成混乱。

答案 1 :(得分:0)

您可以为此使用class Company < ApplicationRecord attr_accessor :user_ids_attribute has_many :company_users has_many :users, through: :company_users after_initialize :assign_attribute after_update :check_users private def assign_attribute self.user_ids_attribute = user_ids end def check_users old_value = user_ids_attribute assign_attribute puts 'Association was changed' unless old_value == user_ids_attribute end end 并检查它是否已更改。

puts

现在,关联更改后,您会在控制台中看到消息。

您可以将"([ ])([0-9]\.)"更改为任何其他方法。

答案 2 :(得分:0)

has_many关系上有一个集合回调before_add,after_add。

class Project
  has_many :developers, after_add: :evaluate_velocity

  def evaluate_velocity(developer)
    #non persisted developer
    ...
  end
end

有关更多详细信息:https://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#label-Association+callbacks