Home > front end >  Rails 6 before save callback not fired
Rails 6 before save callback not fired

Time:11-25

I am trying to assign a random number to an attribute named position before my Product objects are saved. I cannot get the callback to work properly. There are no errors in the console, it just silently fails.

Here is my model

class Product < ApplicationRecord
validates_presence_of :position
before_save {
    assign_position
}

private
    def assign_position
        self.position = rand(150)
    end
end

This is my schema

create_table "products", force: :cascade do |t|
    t.string "name"
    t.integer "position"
end

Here is an example seed I'm using to test the before save callback.

Product.create(name: "Rose Deep Hydration Facial Toner")

There are no errors but the console output when I check after creating the seed

irb(main):079:0> Product.find_by_name("Rose Deep Hydration Facial Toner").position
Product Load (1.8ms)  SELECT "products".* FROM "products" WHERE "products"."name" = $1 ORDER BY "products"."created_at" DESC LIMIT $2  [["name", "Rose Deep Hydration Facial Toner"], ["LIMIT", 1]]
=> nil

I have other callbacks in the application that work just fine. I can't figure out why this one is not working.

CodePudding user response:

Your problem is that validations happen before before_save callbacks are triggered. You have this:

validates_presence_of :position

but position will still be nil when that validation is checked.

I think you want to use a before_validation callback instead of before_save:

class Product < ApplicationRecord
  before_validation :assign_position
  validates_presence_of :position

private

  def assign_position
    self.position = rand(150)
  end
end

Keep in mind that assign_position will get called every time you validate a Product so updating a typo in the name (for example) will change the position. You might want to leave the position alone if it is already set or if you're altering an existing instance.

  • Related