Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails association nil in after_initialize

I have two models with a one to many association. I want to set a default value on the child model at initialization based on some state of the parent. This involves having an after_initialize callback fire on the child that needs to access the parent through the belongs_to association. The problem is that when I instantiate the child using the build method, the association to the parent is nil in the after_initialize callback. Is this expected behaviour? I'm on rails 3.0.6

A toy example:

class Merchant < ActiveRecord::Base
    has_many :products
end

class Product < ActiveRecord::Base
    belongs_to :merchant

    after_initialize :set_default_value

    def set_default_value
        if merchant.state
            self.foo = some_value
        else
            self.foo = some_other_value
        end
    end
end

And in a controller:

product = merchant.products.build

In the call to set_default_value, merchant is nil though it seems that it shouldn't be.

like image 948
Dino Avatar asked Jun 02 '12 18:06

Dino


1 Answers

I would change the code as follows:

class Product < ActiveRecord::Base
  ...
  def set_default_value(state = merchant.state)
    if state
      self.foo = some_value
    else
      self.foo = some_other_value
    end
  end
end

Then change your caller to:

product = merchant.products.build(:state => merchant.state)

Also, I've found after_initialize callbacks to be slow. So another option is to move the logic into the builder for the product.

product = merchant.products.build(:foo => merchant.state ? some_value : some_other_value)

This also eliminates the Law of Demeter violation from the code (i.e. the Product shouldn't know/care what the merchant's state is).

like image 73
Jason Noble Avatar answered Oct 01 '22 15:10

Jason Noble