Search code examples
ruby-on-railsrubyrails-activerecordactivemodel

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


I get a depreciation warning from Rails (5.1.5) when I'm using this customer validation to prevent unwanted changes on a model:

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

Then I get these messages:

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.

Which I understand, except that I'm not using these methods in an after callback. I'd like to catch this before it hits the database/gets saved.

If there's something I'm supposed to use instead (or you guys see a better way of doing this), please let me know.


Solution

  • I figured things out thanks to this earlier answer: https://stackoverflow.com/a/44987787/4983172

    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
    

    Again though, if anyone sees a better way, feel free to throw it in.