ruby-on-rails - 在记录更新时访问关联的先前值

标签 ruby-on-rails ruby-on-rails-3 ruby-on-rails-3.1

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

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

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

有没有更好的方法来解决这个问题?

这是我的更新 Controller 中的代码:

  def update
  params[:event][:invited_user_ids] ||= []
  if @event.update_attributes(params[:event])
    redirect_to @event
  else
    render action: "edit"
  end
  end

我的主要目标是让您可以将用户添加到事件中,但不能删除用户。我想验证发布的 invited_user_ids 是否包含当前受邀的所有用户。

--更新
作为临时解决方案,我使用了 :has_many 关联上的 :before_remove 选项。我将其设置为抛出 ActiveRecord::RollBack 异常,以防止用户不请自来。不完全是我想要的,因为我无法显示验证错误,但它确实阻止了它。

谢谢, 科尔森

最佳答案

你能用ActiveModel::Dirty吗? ?像这样:

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

编辑:我没有注意到 OP 已经打折 ActiveModel::Dirty 因为它不适用于关联。我的错。

另一种可能性是覆盖 invited_user_ids= 方法以将现有用户 ID 附加到给定数组:

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

这应该仍然适用于您,因为 update_attributes 最终会调用各个 attribute= 方法。


编辑:@corsen 在评论中询问为什么我在此示例中使用 alias_method_chain 而不是 super

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

在这种情况下,invited_user_ids 未在 Event 的任何祖先上定义。它是通过元编程直接在 Event 类上定义为 ActiveRecord 的一部分。在 invited_user_ids 中调用 super 将导致 NoMethodError,因为它没有父类(super class)定义,并且重新定义该方法会丢失其原始定义。所以 alias_method_chain 确实是在这种情况下实现类似 super 行为的最简单方法。

有时 alias_method_chain 杀伤力过大,会污染您的命名空间,使跟踪堆栈跟踪变得困难。但有时这是在不丢失原始行为的情况下更改方法行为的最佳方式。您只需要了解其中的区别,就可以知道哪个是合适的。

关于ruby-on-rails - 在记录更新时访问关联的先前值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9445755/

相关文章:

sql - 导致 cpu 达到 100% 的 PostgreSQL 查询。给定 90k 条记录,成本为 7000 可以吗?

ruby-on-rails - 如何使用 SQLite 在 Rails 6 中添加引用列迁移

ruby-on-rails - Rails - Mongoid : newly added fields in model giving nil for old data objects

json - Ruby on Rails JSON.parse 意外 token 错误

ruby-on-rails - ruby 按字母顺序对数组进行排序,唯一并循环 5 次

ruby-on-rails - Rails 控制台不会在 secrets.yml 中加载环境变量

ruby-on-rails - Rails 指南 - 第 11 步 - 多模型表单 - MassAssignmentSecurity 错误

ruby-on-rails - Rails check_box_tag 如何在 ajaxily 检查时传递值

ruby-on-rails-3.1 - file.png 未预编译

ruby-on-rails-3.1 - SASS,导轨 3.1 : Loading stylesheets in vendor/assets