在保存前的验证中使用 changed 和 changed_attributes 会给出折旧警告

Using changed and changed_attributes in validation before saving gives a depreciation warning

当我使用此客户验证来防止对模型进行不必要的更改时,我从 Rails (5.1.5) 收到折旧警告:

class Post < ApplicationRecord
  validate :cannot_change_after_publishing, on: :update

  def cannot_change_after_publishing
    return if changed_attributes.key?(:published_at) && changed_attributes[:published_at].nil?
    # also used this: published_at_changed? && published_at_was.nil?

    unchangeable = %w[message author other_things published_at]
    errors.add(:published_at, "Oh dang!") if changed.any? {|attr| unchangeable.include?(attr)
    # yeah, this isn't the actual message.
  end
end

然后我收到这些消息:

DEPRECATION WARNING: The behavior of `attribute_changed?` inside of after callbacks will be changing in the next version of Rails. The new return value will reflect the behavior of calling the method after `save` returned (e.g. the opposite of what it returns now). To maintain the current behavior, use `saved_change_to_attribute?` instead.
DEPRECATION WARNING: The behavior of `changed` inside of after callbacks will be changing in the next version of Rails. The new return value will reflect the behavior of calling the method after `save` returned (e.g. the opposite of what it returns now). To maintain the current behavior, use `saved_changes.keys` instead.

我明白了,只是我没有在事后回调中使用这些方法。我想在它达到 database/gets 保存之前抓住它。

如果有什么我应该改用的东西(或者你们看到了更好的方法),请告诉我。

以下可能对您有帮助。

class Post < ApplicationRecord

  UNCHANGABLE = %w[message author other_things].freeze
  validate :cannot_change_after_publishing, on: :update

  def cannot_change_after_publishing
    return if saved_change_to_attribute?(:published_at) && changed_attribute_names_to_save[:published_at].nil?

    errors.add(:published_at, "Oh dang!") if UNCHANGABLE.any?{|attr| saved_change_to_attribute?(attr) }
  end
end

ActiveRecord::AttributeMethods::Dirty

多亏了这个较早的回答,我明白了:

class Post < ApplicationRecord
  validate :cannot_change_after_publishing, on: :update

  def cannot_change_after_publishing
    return if published_at_change_to_be_saved && published_at_in_database.nil?

    unchangeable = %w[message author other_things]
    errors.add(:published_at, "Oh dang!") if unchangeable.any? {|attr| changed_attribute_names_to_save.include?(attr)
  end
end

不过,如果有人看到更好的方法,请随意提出。