Luca Romagnoli
Luca Romagnoli

Reputation: 12455

Problems with validations

I have 2 models

class Variant < ActiveRecord::Base
  belongs_to :product
   with_options :if => :is_active? do |p_active|
      p_active.validates :avatar, :presence => true
  end

  with_options :if => :isnt_diavoleria? do |p_active|
    p_active.validates :color, :presence => true
  end
  def is_active?
    self.product.active
  end

  def isnt_diavoleria?
    a = (self.is_active? and self.product.section_id != 5)
    a
  end
end

class Product < ActiveRecord::Base
    has_many :variants, :autosave => true
    accepts_nested_attributes_for :variants
end

If i change the attribute section_id or active of a product and save, the validations of the model variant are executed with the old values of section_id and active. Why?

How can i do the validations with the new values?

Upvotes: 2

Views: 204

Answers (3)

Frederick Cheung
Frederick Cheung

Reputation: 84114

The problem is that by default a pair of has_many and belongs_to associations don't know that they are the inverse of each other. So when you

product.section_id = 23
product.save

then inside your validation, the variant goes

self.product

and actually fetches that from the database again, which obviously doesn't have your unsaved change.

You should be able to fix this by adding the :inverse_of flag to your associations, i.e.

class Variant < AR::Base
  belongs_to :product, :inverse_of => :variants
end
class Product < AR::Base
  has_many :variants, :inverse_of => :products
end

One day rails will have an identity map which should make this sort of stuff less error prone (it is in rails 3.1 but disabled because of subtle associated bugs if i remember correctly)

Upvotes: 3

user1976
user1976

Reputation:

You probably need to do what @thoferon is suggesting (assuming you aren't doing taking nested attributes for products or something) or make sure all changes to the product are happening through the association object so it is up-to-date.

Upvotes: 0

tomferon
tomferon

Reputation: 5001

Maybe you are modifying a product through another Ruby object. The product referenced by the variant is still holding the old values. I don't know if this is what you're doing but it could be the case.

A solution could be to reload the product before validation.

class Variant
  before_validation do
    self.product.reload
  end
end

Upvotes: -1

Related Questions