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

On Jul 1, 1:06 pm, “Birgit (Westhawk)” [email protected] wrote:

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

On 01/07/08 13:47, Frederick C. wrote:

All validates_associated does is run the validations on the associated
Fred

I found the following onlinehttp://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


– Birgit A., [email protected],
– Westhawk Ltd, Albion Wharf, 19 Albion Street, Manchester M1 5LN, UK
– Company no: 1769350
– Registered Office:
– 15 London Road, Stockton Heath, Warrington WA4 6SJ. UK.
– tel.: +44 (0)161 237 0660
– <URL: http://www.westhawk.co.uk>

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

On 1 Jul 2008, at 14:27, Birgit A. wrote:

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

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

On 01/07/08 14:50, “Wolas!” wrote:

@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


– Birgit A., [email protected],
– Westhawk Ltd, Albion Wharf, 19 Albion Street, Manchester M1 5LN, UK
– Company no: 1769350
– Registered Office:
– 15 London Road, Stockton Heath, Warrington WA4 6SJ. UK.
– tel.: +44 (0)161 237 0660
– <URL: http://www.westhawk.co.uk>

Excellent source!!

thx