Rails updating attribute security: use a callback or attr_accessible?
I've got a website model that requires a user to verify ownership of the website.
Thanks to stack overflow, I was able to find the solution for user ownership verification here: Validate website ownership in rails
After the model passes the verification test there is a verified attribute that gets set to true.
The problem I'm running into is when the user wants to edit attributes of his or her website, he or she could easily change the name of the domain while the verified attribute remains true, thus allowing the user to create website objects without verifying ownership.
I can think of two ways to solve this: 1. Have a callback that changes the veri开发者_Go百科fication to false if the domain name of the website gets changed. 2. Allow attr_accessible for the domain upon the creation of a new object but not when updating it.
I'm stumped as to how to implement either of these practically.
Callbacks and Active Record Dirty methods are definitely the way to go for this type of situation.
before_update :set_domain_status
def set_domain_status
self.verified = false if self.domain_changed?
end
_changed? can be added to any attribute, returning true if the value has changed from that originally loaded from the database.
I think your Option#1 is the best route. Otherwise you get into the business of trying to reconcile create and update actions - which you would need to do to handle Option #2.
You could override the setter for domain name and then perform custom logic, like so:
In your Model:
def domain=(the_domain)
raise ValidOwnerRequired if verified? && domain != the_domain
# if we got here then the this record is new and this is a creation attempt
@require_domain_verification = true
# do other stuff here..
end
def require_domain_verification?
@require_domain_verification == true
end
And then have an observer for that model:
def after_save(record)
if record.require_domain_verification?
SomeMailer.deliver_domain_verification(record)
end
end
Something like that...
Cody, your answer got me on the right track. Thanks a lot!
This is what I went for in my case:
def domain=(the_domain)
if domain != the_domain
self[:domain] = the_domain
self[:verified] = false
end
end
It works just fine.
精彩评论