Using before_save to update a record only once.

I'd like to use before_save to perform an action (I won't get into the details), but only the first time the record is changed from 0 to 1. Here's the code I have so far in my model:

def before_save   if completed == 1      # perform the action   end end

What the above does is perform the action when "completed" is set to one, but the problem is I don't want this to happen every single time there is a save. So what I'd like to be able to do is check the previous value of "completed" and only perform the action if it used to be 0 and is now 1. For example (psuedo code):

def before_save   if old_completed == 0 and completed == 1      # perform the action   end end

How would I go about this? Obviously, I could add code outside the model, but before_save seems like the nicest, cleanest place to for this code to be. I searched this forum and found a post that kind of helps answer my question, but it's not super clear and I'm still not sure what the best solution is. It sounds like I have to do an external find just to do this check, and that just doesn't seem right to me. Is that really the only way?

Don't have a specific answer for you, but the acts_as_changed plugin might come in handy for you...

http://agilewebdevelopment.com/plugins/acts_as_changed

-philip

Philip Hallstrom wrote:

What the above does is perform the action when "completed" is set to

How would I go about this? Obviously, I could add code outside the model, but before_save seems like the nicest, cleanest place to for this code to be. I searched this forum and found a post that kind of helps answer my question, but it's not super clear and I'm still not sure what the best solution is. It sounds like I have to do an external find just to do this check, and that just doesn't seem right to me. Is that really the only way?

Don't have a specific answer for you, but the acts_as_changed plugin might come in handy for you...

http://agilewebdevelopment.com/plugins/acts_as_changed

-philip

Thanks, Philip. I'm having a difficult time understanding exactly what it does. The one line explanation isn't 100% clear to me. It sort of looks like a speed related plug-in that simply updates fields that been changed, rather than going through each field in the entire table, but I could be wrong about that.

I've never used it myself :slight_smile: ANd I think you're right about that. There's a "changed_attributes" method that returns what's changed though that you could use perhaps...

Guess I thought it might provide more inspiration than an outright answer :slight_smile:

Thinking more about it, you could override the completed method to record that it was changed and then check that in your before_save...

-philip

Philip Hallstrom wrote:

changed, rather than going through each field in the entire table, but I could be wrong about that.

I've never used it myself :slight_smile: ANd I think you're right about that. There's a "changed_attributes" method that returns what's changed though that you could use perhaps...

Guess I thought it might provide more inspiration than an outright answer :slight_smile:

Thinking more about it, you could override the completed method to record that it was changed and then check that in your before_save...

-philip

Sorry I'm a little late here -- been away for a couple days. That sounds interesting. Can you explain in more detail how I'd do something like that?

Hrm... something like this assuming your model has 'completed' attribute.

class MyModel < ...

   attr :is_complete

   def completed=(val)      if completed == 0 && val == 1 then        is_complete = true      else        is_complete = false      end      completed = val    end

   def before_save      if is_complete != true then        return false      end      true    end

end

MenDAKE :

My code looks something like this:

class MyModel < ActiveRecord::Base   attr :completed_is_changed

  # This checks to see if the completed fiel was set to true for the first time.   def completed=(val)     if completed == 0 && val == 1       completed_is_changed = true     else       completed_is_changed = false     end

    completed = val   end

  def before_save     if completed_is_changed == true        #perform the action.     end end

The actions are performed, but the completed field value is now never saved to the database. I would expect that the line "completed = val" would take care of that, but it doesn't seem to. Is something missing?

You can write it like that :

def completed=(val)   completed_is_changed = completed == 0 && val == 1   write_attribute(:completed, val) end

   -- Jean-François.

Philip Hallstrom wrote:

answer

that?

Hrm... something like this assuming your model has 'completed' attribute.

class MyModel < ...

   attr :is_complete

   def completed=(val)      if completed == 0 && val == 1 then        is_complete = true      else        is_complete = false      end      completed = val

Ah, I suspect this is it... do something like...

self['completed'] = val

or whatever rails does by default for this thing...