Forum: Ruby on Rails Re: many to many link table compound primary key explosion

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
4cacb94a089bfbf0541db7b9c8081f74?d=identicon&s=25 Kevin Bedell (Guest)
on 2006-01-05 06:04
(Received via mailing list)
I think to begin with, an appropriate change to your data model would
be:

create table answers_questions (
  id int not null autoincrement,
  question_id int unsigned not null,
  answer_id int unsigned not null,
  constraint fk_qid foreign key (question_id) references questions(id),
  constraint fk_aid foreign key (answer_id) references answers(id),
  primary key (id)
) ENGINE=InnoDB;

In general, it's considered better practice to have primary keys be
'meaningless' and not use them to implement what essentially is a
business
rule.

You can then implement uniqueness on the two foreign keys directly in
active
record using the built in validation capabilities it provides to ensure
that
you  don't get duplicates.

For info on validation, see:

     http://api.rubyonrails.com/classes/ActiveRecord/Va...

You have a choice to put the validation logic in the database or put it
in the
ActiveRecord models. There are reasons to go either way, but in this
case
pulling the valdation out of the database and putting it in the
ActiveRecord
models looks like it may be easier nd give you more flexibility.



--
Kevin Bedell
http://www.kbedell.com

"The future belongs to those who believe in the beauty of their dreams."
- Eleanor Roosevelt



----- End forwarded message -----


--
Kevin Bedell
http://www.kbedell.com

"The future belongs to those who believe in the beauty of their dreams."
 - Eleanor Roosevelt
28c237c0c414b644082bfcde4e42b309?d=identicon&s=25 John Leach (Guest)
on 2006-01-05 10:38
(Received via mailing list)
Hi Kevin,

thanks for the advice.

I don't believe changing my data model is the right thing here.  For a
start it's already helped me identify this potential problem :)

Also, those rows are already unique by the combination of answer_id and
question_id.  Adding a new primary key called id is meaningless.

An additional problem is that ActiveRecord includes all columns from the
link table when joining the linked table, so the id field would collide
(the link table id would take preference as I understand).

Technically, the primary keys in this instance aren't implementing a
business rule.  The link table should never include duplicate link
records.  At the end of the day, I'm trying to do something that
violates this rule, which is wrong.  Perhaps the best course of action
is just to figure out a graceful way to handle it in my code.  I don't
know how to override the @question.answers.push method, if this were to
be the best option.

John.
http://johnleach.co.uk

p.s: Having just tested it, I see that without this compound primary
key, rails creates duplicate rows as I suspected.
A2c85dc5ee81b12e3cc0a6522e8d079d?d=identicon&s=25 Chris Hall (Guest)
on 2006-01-05 12:48
(Received via mailing list)
I agree that putting an id column in the join table is a bad idea
because of
the 'clobbering' that will happen.  The documentation even mentions
this.
Not to say that you can't, but you would then have to create a different
relationship between the models

questions (hm)...(bt) answers_questions (bt)...(hm) answers

and answers_questions would become a model

I might recommend the following however

class Question < AR::Base
  has_and_belongs_to_many :answers

  # only add the answer to the question only if the answer is not
already
associated
  def add_answer(answer)
    answers << answer unless answers.include?(answer)
  end
end

a = Answer.create(...)
q = Question.find(1)
q.add_answer(a)
28c237c0c414b644082bfcde4e42b309?d=identicon&s=25 John Leach (Guest)
on 2006-01-05 13:39
(Received via mailing list)
Hi Chris,

thanks, I'll use that method.

Do you think ActiveRecord's behaviour is correct?  Or should it check
for duplicates itself here?  Without a compound primary key this might
have gone undetected and I think DHH's "single layer of cleverness"[1]
post has people believing the db shouldn't be checking this stuff.

Should I perhaps file a bug?

John.
http://johnleach.co.uk


[1] http://www.loudthinking.com/arc/000516.html
I'm not suggesting that *is* what DHH is saying though :)
This topic is locked and can not be replied to.