Gareth Burrows
Gareth Burrows

Reputation: 41

before_save except on new record if field value changes

I need to execute a hook in a rails4 app if a field changes and only if its not a record record.

I know I can do...

  before_save :reset_confirmation, if: :email_changed?
  def reset_confirmation
    self.confirmed_at = nil
    self.confirmation_sent_at = nil
  end

and I'm pretty sure this works...

  before_save :reset_confirmation, unless: new_record?
  def reset_confirmation
    self.confirmed_at = nil
    self.confirmation_sent_at = nil
  end

but how do I combine the two, or is there an easier way to achieve what I want and I'm overthinking things. The field (email) will always contains a value after it's been created if that helps?

Upvotes: 1

Views: 2224

Answers (3)

spickermann
spickermann

Reputation: 106882

I wonder if the readability and maintainability of the class improve when the callback is replaced by an explicit setter method:

def email=(new_email)
  unless new_email == email 
    self.confirmed_at = nil
    self.confirmation_sent_at = nil
    write_attribute(:email, new_email)
  end
end

Upvotes: 0

Gareth Burrows
Gareth Burrows

Reputation: 41

I went with this in the end...

  before_update :reset_confirmation, if: :email_changed?
  def reset_confirmation
    self.confirmed_at = nil
    self.confirmation_sent_at = nil
  end

with the logic being that before_update only runs on existing records, which takes care of the new record issue, and now it doesn't step into the method unless the condition has been met to reset the fields anyway.

Upvotes: 0

Gerry
Gerry

Reputation: 10497

You can use multiple conditions in your callback, like this:

before_save :reset_confirmation, if: :email_changed?, unless: :new_record?

def reset_confirmation
  self.confirmed_at = nil
  self.confirmation_sent_at = nil
end

Or, you could add another method to check both conditions, for example:

before_save :reset_confirmation, if: :email_changed_and_its_not_new_record?

def reset_confirmation
  self.confirmed_at = nil
  self.confirmation_sent_at = nil
end

def email_changed_and_its_not_new_record?
  email_changed? && !new_record?
end

You can find more information for conditional callbacks here.

Upvotes: 2

Related Questions