C'est une vrai question à laquelle je n'ai pas de réponse. Pourtant ça me paraît tellement naturel que je me demande s'il y a une raison technique à ça.

Ci dessous quelques exemples pour illustrer:

class Contract < ActiveRecord::Base
  belongs_to :sender, :class_name => "Company"
  belongs_to :receiver, :class_name => "Company"
end

On commence à imaginer le problème qui va se poser, deux relations qui pointent vers une même classe. Voyons un peu le SQL généré en faisant des jointures.

Contract.all(:joins => [:sender, :receiver])

=>

SELECT `contracts`.* FROM `contracts` INNER JOIN `companies` ON `companies`.id = `contracts`.sender_id INNER JOIN `companies` receivers_contracts ON `receivers_contracts`.id = `contracts`.receiver_id

Pour sender AR va donc conserver le nom de la table originale. Pour receiver comme le nom de table companies est déjà utilisé il va devoir en utiliser un autre (receivers_contracts).

D'où ma question: pourquoi ne pas utiliser le nom de l'association (et de façon systématique) ?

Je ne vois pas d'obstacle à cela dans la mesure où le nom de l'association risque fort d'être unique. Le seul problème que je vois est une jointure du même nom dans une classe déjà jointe. Par exemple si Company possédait une jointure nommée sender qu'on voulait utiliser dans le même temps.

Mais dans ce cas précis on pourrait utiliser des alias du style receivers_contracts partout pour générer un:

SELECT `contracts`.* FROM `contracts` INNER JOIN `companies` senders_contracts ON `senders_contracts`.id = `contracts`.sender_id INNER JOIN `companies` receivers_contracts ON `receivers_contracts`.id = `contracts`.receiver_id

Actuellement on ne peut pas faire de:

Contract.all(:joins => [:sender, :receiver], :conditions => { :sender => { :name => "foo" } })

Pire, quand on ne connaît pas le comportement par défaut d'AR il faut être devin pour savoir ce que fait:

Contract.all(:joins => [:sender, :receiver], :conditions => { :companies => { :name => "foo" } })

Est ce que je suis entrain de filtrer sur l'expéditeur ou le destinataire ?

Si on veut faire notre recherche en utilisant AR il faudrait donc faire:

Contract.all(:joins => [:sender, :receiver], :conditions => { :companies => { :name => "foo"}, :receivers_bills => { :name => "bar" } })

On ne peut pas dire que ce soit très élégant ni intuitif.

Pourtant ce SQL fonctionne:

SELECT `contracts`.* FROM `contracts` INNER JOIN `companies` sender ON `sender`.id = `contracts`.sender_id INNER JOIN companies receiver ON receiver.id = contracts.receiver_id WHERE (`sender`.`name` = 'foo' AND `receiver`.`name` = 'bar');

Si quelqu'un a une explication logique à ça je suis preneur.