MCMatan
MCMatan

Reputation: 8843

How to update one attribute when other changes

I am new to Rails and can get this right.

Trying to update "completed_at" when "completed" turns true.

I've read this: https://api.rubyonrails.org/classes/ActiveModel/Dirty.html#method-i-changed-3F

And decided to add a callback, on each update or save. Then check if the "completed" prop has changed, if not, if it is true, update "completed_at" to the current date.

The method "check_is_completed" does get called, but I can't access the correct prop's and detect if changed and get the new value

class Task < ApplicationRecord
  belongs_to :user
  validates :name, presence: true

  after_save :check_is_completed
  after_update :check_is_completed

  private 

  # This gets called
  def check_is_completed
    # try 1
    # This does not work called
    if @completed.changed?
      if @completed == true
      self.completed_at = Date.new()
      end
    end
    #try 2
    if self.completed_changed?
      if self.completed == true
      self.completed_at = Date.new()
      end
    end
  end
end

Upvotes: 2

Views: 1495

Answers (1)

Mark
Mark

Reputation: 6455

You're pretty much there. Your issue is that you're performing your check after you save instead of before. After you've saved the record, the update has already taken place, so the system thinks nothing has changed.

Change

  after_save :check_is_completed
  after_update :check_is_completed

To

  before_save :check_is_completed

You also won't need to use any instance variables. As you're already in your class, all you need to do is:

def check_is_completed
  return unless completed_changed?
  self.completed_at = Date.new() if completed?
end

This will perform the check before every save, doing nothing unless the completed attribute has changed, and then only updating the completed_at field if completed is true

Upvotes: 5

Related Questions