Ruby on rails 在记录更新时访问以前的关联值

Ruby on rails 在记录更新时访问以前的关联值,ruby-on-rails,ruby-on-rails-3,ruby-on-rails-3.1,Ruby On Rails,Ruby On Rails 3,Ruby On Rails 3.1,我有一个“事件”模型,它有许多“邀请”。通过活动表单上的复选框设置邀请。更新活动时,我想比较更新前的邀请和更新后的邀请。我想将此作为活动验证的一部分 我的问题是,我似乎无法访问任何模型回调或验证中的旧邀请。此时事务已经开始,因为邀请不是事件模型的属性,所以我不能使用_was来获取旧值 我想尝试使用一个“after_initialize”回调来自己存储它。这些回调似乎不尊重“:on”选项,所以我不能只执行:on:update。我不想每次初始化对象时都运行这个 有没有更好的办法解决这个问题 以下是我

我有一个“事件”模型,它有许多“邀请”。通过活动表单上的复选框设置邀请。更新活动时,我想比较更新前的邀请和更新后的邀请。我想将此作为活动验证的一部分

我的问题是,我似乎无法访问任何模型回调或验证中的旧邀请。此时事务已经开始,因为邀请不是事件模型的属性,所以我不能使用_was来获取旧值

我想尝试使用一个“after_initialize”回调来自己存储它。这些回调似乎不尊重“:on”选项,所以我不能只执行:on:update。我不想每次初始化对象时都运行这个

有没有更好的办法解决这个问题

以下是我的更新控制器中的代码:

  def update
  params[:event][:invited_user_ids] ||= []
  if @event.update_attributes(params[:event])
    redirect_to @event
  else
    render action: "edit"
  end
  end
我的主要目标是使它能够向事件添加用户,但不能删除用户。我想验证发布的受邀请用户ID是否包含当前受邀请的所有用户

--更新
作为临时解决方案,我在:has\u many关联上使用了:before\u remove选项。我将其设置为抛出ActiveRecord::RollBack异常,以防止用户不被邀请。这不是我想要的,因为我无法显示验证错误,但它确实阻止了验证错误

谢谢,, 科森,你能用一下吗?大概是这样的:

def Event < ActiveRecord::Base
  validates :no_invitees_removed

  def no_invitees_removed
    if invitees.changed? && (invitees - invitees_was).present?
      # ... add an error or re-add the missing invitees
    end
  end
end
这仍然适用于您,因为
update\u attributes
最终会调用单个
attribute=
方法


Edit:@corsen在评论中问我为什么在本例中使用
alias\u method\u chain
而不是
super

调用
super
仅在重写继承链更上层定义的方法时有效。混合在一个模块中或从另一个类继承提供了一种实现这一点的方法。该模块或类不会直接向派生类“添加”方法。相反,它将自己插入该类的继承链中。然后,您可以在派生类中重新定义方法,而不会破坏方法的原始定义(因为它们仍然在超类/模块中)

在这种情况下,
邀请的用户ID
未在
事件的任何祖先上定义。它是通过元编程直接在
事件
类上定义的,作为ActiveRecord的一部分。在
invested\u user\u id
中调用
super
将导致
NoMethodError
,因为它没有超类定义,重新定义方法将丢失其原始定义。因此,在这种情况下,
alias\u-method\u-chain
确实是实现
super
类行为的最简单方法


有时,
alias\u method\u chain
会过度使用并污染您的命名空间,使跟踪堆栈跟踪变得困难。但有时这是在不丢失原始行为的情况下更改方法行为的最佳方法。您只需要了解其中的差异,就可以知道哪一个是合适的。

您可以向我们展示用于更新活动和邀请的代码吗?我添加了控制器的更新操作。我正在使用自动生成的邀请用户ID方法来更新关联。我不想让它删除任何以前的选择,而是只添加新的。不,我希望我可以。但是活动邀请了很多人。它不是模型的属性,而是关联。ActiveModel::Dirty没有跟踪它。除非我弄错了:)对不起,你是对的。我在你原来的帖子里漏掉了。我在我的答案中添加了另一个建议。这很有效,而且似乎很容易。我是Ruby/Rails新手,以前从未听说过alias\u method\u chain。在做了一些研究之后,我发现关于使用这个与继承/超级的比较存在一些争论。继承/超级的实现似乎比这个更复杂,所以我将接受这个解决方案,因为它工作得很好。如果您能详细说明使用继承/超级是否也适用于此,那就太好了。这对我很有帮助,因为我是Ruby/Rails新手。它太长了,无法发表评论:-)
class Event < ActiveRecord::Base
  # ...

  def invited_user_ids_with_guard=(ids)
    self.invited_user_ids_without_guard = self.invited_user_ids.concat(ids).uniq
  end
  alias_method_chain :invited_user_ids=, :guard
end