Hi
I remember once I read about to get only updated fields from an
update_attributes method. Means say I have a model user with
name,age,sex etc And when the user updates the information I have to
first check whether he actually updated anything(There is a chance that
update button from view simply being clicked) and if only any updates
happened I have to get that updated fields and send a mail stating that
these fields are updated. How can I do this. Suppose in the above
example if only name updated
If you look at the source code for update_attributes, you'll see it
does a "save" in the method, so once it's finished, the are no changed
fields (because the record has already been updated).
You need a callback filter to run in your User model; and
"before_save" seems sensible to me:
Hi
Thank you. I have one more thing to clarify . If I write a
before_save filter as you suggested, then will mail be sent when ever
there is an update or save to this User model ? That is not what I want
if it behaves like that.Please excuse if I am wrong
If you look at the source code for update_attributes, you’ll see it
does a “save” in the method, so once it’s finished, the are no changed
fields (because the record has already been updated).
You need a callback filter to run in your User model; and
“before_save” seems sensible to me:
Or alternatively, as you’re looking at the source for ActiveRecord::Base you’ll see that the update_attributes method simply does this:
def update_attributes(attributes)
self.attributes = attributes
save
end
So, instead of messing about with callbacks, you could simply amend your original code to this (assigning to attributes rather than calling update_attributes):
@user = User.find(params[:id])
if @user.attributes = params[:user]
send_mail if @user.changed? #But this is always returns false Not
While technically you’re right (and therefore it may make more sense to move it to the model - @user.update_attributes_and_notify), it seems (from reading between the OP’s lines) like there are a number of places where he’d want to update the user himself (and not send an email) and only have it send the email from a particular place/action.
I completely agree about DRYness, but I was just offering an alternative solution as we don’t know the full facts in what he’s trying to do.
we don't know the full facts in what he's trying to do.
Agreed - the "oh, but I didn't tell you about this condition" syndrome.
Let's split the difference... create a method on the user model that
checks for .changed? and sends the email, but rather than using it as
an AR callback to hook *every* update, call it from those controller
methods you want to, and use the default update_attributes
elsewhere... how's that sound?
Something along the lines of:
# User model
def update_attributes_and_notify
self.attributes = attributes
send_email if changed?
save
end
# Users controller
@user = User.find(params[:id])
if @user.update_attributes_and_notify(params[:user])
working
Hi
I solved it as Michael suggested And it was working .But now i
notified another issue. That is why reopening the thread. The issue is,
even if the validations fail, mail is sent to user (What I need is only
if update happens successfully on changed attributes then only mail to
be sent)
controller code is
@user = User.find(params[:id])
res = @user.update_attributes_and_notify(params[:user])
if res == true
----do this
elsif res == false
----do this
elsif res == 'nochange'
----do this
end
User model code is
def update_attributes_and_notify(attributes,user)
self.attributes = attributes
if changed?
deliver_user_edit_details!
save
else
return 'nochange'
end
end
and if I change the line in model
deliver_user_edit_details! if save
I get error
undefined method `call' for nil:NilClass