validates_associated & foreign keys

Hi,

I'm struggling to get the validates_associated to work as I think it should be.

I'm using: JRuby 1.1 rails-2.0.2 activerecord-2.0.2 activerecord-jdbc-adapter-0.8.2

My tables in MySQL: CREATE TABLE area_codes (     id INT UNSIGNED auto_increment primary key ... );

CREATE TABLE markets (     id INT UNSIGNED auto_increment primary key, ... );

CREATE TABLE area_codes_markets (     id INT UNSIGNED auto_increment primary key,     market_id INT UNSIGNED NOT NULL,     area_code_id INT UNSIGNED NOT NULL,     INDEX(market_id),     INDEX(area_code_id),     CONSTRAINT UNIQUE (market_id, area_code_id),     CONSTRAINT FOREIGN KEY(market_id)         REFERENCES markets(id) MATCH FULL ON DELETE RESTRICT,     CONSTRAINT FOREIGN KEY(area_code_id)         REFERENCES area_codes(id) MATCH FULL ON DELETE RESTRICT ) ENGINE=InnoDB;

My model: class AreaCodesMarket < ActiveRecord::Base   has_many :area_codes   has_many :markets   validates_associated :area_codes   validates_associated :markets

  validates_presence_of :area_code_id, :market_id   validates_uniqueness_of :market_id, :scope => :area_code_id end

When I create a new area_codes_market record and (deliberately) enter an area_code_id or a market_id that is incorrect, Ruby on Rails doesn't flag the error. Instead I get an activerecord error on my foreign key constraint.

ActiveRecord::ActiveRecordError: Cannot add or update a child row: a foreign key constraint fails (`TestDoneRight_test`.`area_codes_markets`, CONSTRAINT `area_codes_markets_ibfk_2` FOREIGN KEY (`area_code_id`) REFERENCES `area_codes` (`id`)): INSERT INTO `area_codes_markets` (`area_code_id`, `market_id`) VALUES(2, 1)

Reading the forums and the documentation, I think I have the correct naming convention and model.

I found the following online http://dev.rubyonrails.org/ticket/5369 However, the patch is for an older ActiveRecord version, so I've got no idea how to apply it (assuming it would even work).

Does anyone have a clue how I could fix this?

Thanks, Birgit

When I create a new area_codes_market record and (deliberately) enter an area_code_id or a market_id that is incorrect, Ruby on Rails doesn't flag the error. Instead I get an activerecord error on my foreign key constraint.

I think you've just set your hopes a little too high - rails doesn't really do anything with foreign keys. All validates_associated does is run the validations on the associated models. If you were about to create a record with a dangling reference then there's just nothing for validates_associated to validate.

On top of that i think you've got your associations wired up the wrong way round. Given that you've got area_code_id and market_id columns (and going by the name of your table) you should have belongs_to :area_code and belongs_to :market not the has_manys you've currently got (has_many area_codes implies that area_codes has a area_codes_market_id column)

Fred

Hi Frederick,

Thanks for your message. I changed my 'belongs_to' and 'has_many' and (indeed) the problem persists.

I know that RoR doesn't really know about foreign keys, but what is the purpose of validates_associated ?? http://ar.rubyonrails.com/classes/ActiveRecord/Validations/ClassMethods.html#M000090

What kind of associating does it perform, it not on the values between two models?

Maybe I should rephrase my question ...

If validates_associated doesn't do the trick, how do I write a validation that checks that area_codes_market.area_code_id == area_codes.id

Thanks, Birgit

Hi Frederick,

Thanks for your message. I changed my 'belongs_to' and 'has_many' and (indeed) the problem persists.

I know that RoR doesn't really know about foreign keys, but what is the purpose of validates_associated ?? Peak Obsession

It runs the validations on the association. If there is no associated model (eg because the foreign key is dangling) it doesn't care

What kind of associating does it perform, it not on the values between two models?

Maybe I should rephrase my question ...

If validates_associated doesn't do the trick, how do I write a validation that checks that area_codes_market.area_code_id == area_codes.id

From the api docs:

NOTE: This validation will not fail if the association hasn't been assigned. If you want to ensure that the association is both present and guaranteed to be valid, you also need to use validates_presence_of.

Fred

The purpose of validates_associated is to know whether an object associated with another object is valid (as in returns true when calling the valid? method) This allows you, for example to check whether an area code object associated to a market is valid before you save both. if the associated object fails validation, then the parent object cannot be saved either.

What Frederick is talking about (dangling references) is a check that rails will not do for you on write (as in creating a row in the db) but on read. Specifically on method calls to other objects.

So for instance i can create Product.new(:category_id => 2) where product belongs to category. I save it no trouble, even change the category_id later on

@product.category_id = 999 => 999 @product.save => true

but then:

@product.category => nil # if Category.find_by_id(999) is nil

@product.category_id => 999 dunno if this helps, just thought it could shine some light for people with similar problems

Thanks Wolas and Fred for you help and explanation.

I've decided to change the UI of market, so it will display checkboxes for the available area_codes. This way I avoid having the check for foreign keys, since the UI will only offer what's available.

For newbies (such as myself, specially when using Rails 2.0 and getting very confused when looking at Rails 1.X examples), the following really helped me out:

PaulBarry.com - has_many :through checkboxes http://paulbarry.com/articles/2007/10/24/has_many-through-checkboxes

Cheers, Birgit

Excellent source!!

thx