Why is before_save not getting called for my ActiveRecord model?
As you can see in the documentation, before_save
happens after validation. In your case, validation will fail and before_save
will never be invoked.
Since the goal of your callback is to set your object to a valid state before validation happens, try the before_validation
callback.
Chad Johnson
Actively developing web applications since 2000. Extensive architectural and developmental experience in both backend and frontend development with focuses on Node.js and React. Specializing in ecommerce with exposure to multiple industries.
Updated on July 06, 2022Comments
-
Chad Johnson almost 2 years
Nothing prints out to the console when I use IRB to create a new model instance and save, and I get a "ActiveRecord::StatementInvalid: Mysql::Error: Column 'user_id' cannot be null" error, so I assume before_save is not getting called. I can't figure out why. I've even tried using the before_save filter. Here's my code:
require 'secure_resource/secure_resource_encryption' class Database < ActiveRecord::Base belongs_to :username_encryption, :class_name => "Encryption", :foreign_key => :username_encryption_id belongs_to :password_encryption, :class_name => "Encryption", :foreign_key => :password_encryption_id # Virtual attribute to retrieve the decrypted username. def username if self.username_encryption.nil? return nil end begin return self.username_encryption.encryption rescue SecureResourceError raise SecureResourceError end end # Provides a way to reset the username. def username=(username) if self.username_encryption.nil? self.username_encryption = Encryption.new self.username_encryption.encryption = username end end # Virtual attribute to retrieve the decrypted password. def password if password_encryption.nil? return nil end begin return password_encryption.encryption rescue SecureResourceError raise SecureResourceError end end # Provides a way to reset the password. def password=(password) if self.password_encryption.nil? self.password_encryption = Encryption.new self.password_encryption.encryption = password end end def before_save p 'ZZZZZZZZZZZZZZZ' p self.user_id.to_s + ' ZZZZZZ' p 'ZZZZZZZZZZZZZZZ' self.username_encryption.user_id = self.user_id self.username_encryption.save self.username_encryption_id = self.username_encryption.id self.password_encryption.user_id = self.user_id self.password_encryption.save self.password_encryption_id = self.password_encryption.id end end
-
Chad Johnson almost 13 yearsAhh, so the MySQL error is happening during validation. For some reason I had assumed it was happening during save. I'll give this a try and see what happens. How can I explicitly tell if validation passes?
-
Chad Johnson almost 13 yearsThing is, in IRB, when I create a new Database instance, set parameters, and call database.valid?, true is returned. So how could this possibly be a validation issue?
-
user229044 almost 13 years@Chad Ah, I didn't read closely enough. If MySQL is raising the error, your
before_validation
andbefore_save
callbacks have fired and Rails is talking to the database. One of youruser_id
fields is null. Try usinglogger.info
instead ofputs
/p
, which do not write to the console in Rails. -
Chad Johnson almost 13 yearsUsing before_validation worked. Validation was failing because I was creating an encryption record inside the database model in some method (ie. self.username_encryption = Encryption.new in Database.some_method). Then I was trying to set some properties of self.username_encryption in the before_save hook of the database class, and for some reason I couldn't set properties on self.username_encryption, so, when I called database.save, validation for the database object failed.
-
Tilo over 7 yearsI see this happening in Rails 4.2.4 although the validation passes!