I was fighting with virtual attributes for a few hours, and I'll share what I did wrong:
Here's a model with one virtual attribute as well as a text field
class User < ActiveRecord::Base
attr_accessible :sanity_level
attr_accessor :sanity_level
validates_presence_of :sanity_level, :on => :update
end
I would expect the following to work:
user = User.create(:name => "Leif")
user.save(:sanity_level => 5)
user.valid?
# => false # What?
user.errors.inspect
# => Errors show: Sanity Level cannot be blank... but it is 5?
user.update_attributes(:sanity_level => 5)
user.valid?
# => true
I expected both to work, but it doesn't by design. After looking at activerecord and mysql2 source, it is easly spotted that save calls create_or_update without forwarding the hash, so of course it will fail!
To summarize and remember for the future:
- Use update_attributes when updating with a hash for the attributes to update
- Use save after setting attributes manually
- Use create when creating new records
- Use build when building new records with a hash and saving later
And a note to myself again:
Don't use save when updating attributes.