user
user

Reputation: 3456

Why is before_create not being called here?

Similar question, but user was not actually creating an ActiveRecord object.

Following Michael Hartl's tutorial, and I've hit a wall. There is a method call in before_save that doesn't seem to be working. I have double checked that my code aligns with his and is syntactically valid (although I often overlook simple syntax errors).

class User < ActiveRecord::Base
    before_create { :create_remember_token }    <------ here
    before_save { self.email = email.downcase }

    validates :name, presence: true, length: { maximum: 30 }

    VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.?]+\.[a-z]{2,4}\z/i
    validates :email,   presence: true, 
                        format: { with: VALID_EMAIL_REGEX }, 
                        uniqueness: { case_sensitive: false }

    has_secure_password # automatically checks presence of password and confirmation
    validates :password, length: { minimum: 6 } 


    def User.new_remember_token
        SecureRandom.urlsafe_base64
    end

    def User.encrypt(token)
        Digest::SHA1.hexdigest(token.to_s)
    end

 private

    def create_remember_token
        self.remember_token = User.encrypt(User.new_remember_token)
    end

end

Here's a console session to show that the db schema includes a remember_token, the class methods indeed work, yet something is wrong with the create callback.

2.0.0p247 :001 > User
 => User(id: integer, name: string, email: string, created_at: datetime, updated_at: datetime, password_digest: string, remember_token: string) 
2.0.0p247 :002 > User.create(name:"Confused", email:"[email protected]", password:"password", password_confirmation:"password")
   (0.1ms)  begin transaction
  User Exists (0.2ms)  SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('[email protected]') LIMIT 1
Binary data inserted for `string` type on column `password_digest`
  SQL (3.9ms)  INSERT INTO "users" ("created_at", "email", "name", "password_digest", "updated_at") VALUES (?, ?, ?, ?, ?)  [["created_at", Wed, 09 Oct 2013 22:50:41 UTC +00:00], ["email", "[email protected]"], ["name", "Confused"], ["password_digest", "$2a$10$Pca7ZokAVlca/floQRY1KesM1SFoSfiUxWjEJ8xHyA4NJueK4GVbG"], ["updated_at", Wed, 09 Oct 2013 22:50:41 UTC +00:00]]
   (101.5ms)  commit transaction
 => #<User id: 9, name: "Confused", email: "[email protected]", created_at: "2013-10-09 22:50:41", updated_at: "2013-10-09 22:50:41", password_digest: "$2a$10$Pca7ZokAVlca/floQRY1KesM1SFoSfiUxWjEJ8xHyA4N...", remember_token: nil> 
2.0.0p247 :003 > 
2.0.0p247 :004 >   token = User.new_remember_token
 => "md1vrpB2PH1VNMWaliuT6g" 
2.0.0p247 :005 > User.encrypt(token)
 => "522d45ee2771c2cb36ffe6536b316ad004e5038b" 
2.0.0p247 :006 > 
2.0.0p247 :006 > User._create_callbacks.select { |cb| cb.kind.eql?(:before) }.collect(&:filter).include?(:create_remember_token)
 => false 

Upvotes: 0

Views: 851

Answers (1)

Pawel
Pawel

Reputation: 944

Just remove brackets, try:

before_create :create_remember_token 

If you pass a block it is evaluated, if you pass symbol a method with given name is called.

Upvotes: 3

Related Questions