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?
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…
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…
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.
changed, rather than going through each field in the entire table, but I
could be wrong about that.
I’ve never used it myself 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
Thinking more about it, you could override the completed method to
record
that it was changed and then check that in your before_save…
changed, rather than going through each field in the entire table, but I
could be wrong about that.
I’ve never used it myself 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
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?
Of course there is another way, you could write your own plugin
acts_as_update_once to do this across all your controllers. Make sure
that the logic you use short-circuits quickly for the condition that
happens most of the time. This way performance will be good.
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
end
def before_save
if is_complete != true then
return false
end
true
end
end
Thanks, that makes sense. I implemented something similar to your
example, but for some reason the completed field now never gets saved.
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?
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