Question

J'ai un ActiveRecord appelé Name qui contient les noms dans divers Languages.

class Name < ActiveRecord::Base
  belongs_to :language

class Language < ActiveRecord::Base
  has_many :names

Les noms Trouver dans une langue est assez facile:

Language.find(1).names.find(whatever)

Mais je dois trouver des paires de correspondance où les deux langues 1 et la langue 2 ont le même nom. Dans SQL, ce qui exige une simple auto-inscription:

SELECT n1.id,n2.id FROM names AS n1, names AS n2
  WHERE n1.language_id=1 AND n2.language_id=2
    AND n1.normalized=n2.normalized AND n1.id != n2.id;

Comment puis-je faire une requête comme ça avec ActiveRecord? Notez que je dois trouver des paires de noms (= les deux côtés du match), et pas seulement une liste de noms dans la langue 1 qui arrive à correspondre à quelque chose.

Pour les points de bonus, remplacer n1.normalized=n2.normalized avec n1.normalized LIKE n2.normalized, puisque le champ peut contenir des jokers SQL.

Je suis aussi ouvert aux idées sur la modélisation des données différemment, mais je préfère éviter d'avoir des tables séparées pour chaque langue si je peux.

Était-ce utile?

La solution

Essayez ceci:

ids = [1,2]
Name.all(:select    => "names.id, n2.id AS id2",
         :joins     => "JOIN names AS n2 
                              ON n2.normalized = names.normalized AND 
                                 n2.language_id != names.language_id AND
                                 n2.language_id IN (%s)" % ids.join(','),
         :conditions => ["names.language_id IN (?)", ids]
).each do |name|
  p "id1 : #{name.id}"
  p "id2 : #{name.id2}"
end

PS:. Assurez-vous désinfectez les paramètres passés à la condition de jointure

Autres conseils

On dirait que vous pouvez utiliser plusieurs à plusieurs entre la langue et le nom au lieu de has_many / belongs_to.

>> Language.create(:name => 'English')
 => #<Language id: 3, name: "English", created_at: "2010-09-04 19:15:11", updated_at: "2010-09-04 19:15:11"> 
>> Language.create(:name => 'French')
 => #<Language id: 4, name: "French", created_at: "2010-09-04 19:15:13", updated_at: "2010-09-04 19:15:13"> 
>> Language.first.names << Name.find_or_create_by_name('Dave')
 => [#<Name id: 3, name: "Dave", language_id: 3, created_at: "2010-09-04 19:16:50", updated_at: "2010-09-04 19:16:50">] 
>> Language.last.names << Name.find_or_create_by_name('Dave')
 => [#<Name id: 3, name: "Dave", language_id: 4, created_at: "2010-09-04 19:16:50", updated_at: "2010-09-04 19:16:50">]
>> Language.first.names.first.languages.map(&:name)
 => ["English", "French"] 

Ce niveau de normalisation supplémentaire devrait faire ce que vous essayez de faire plus facile.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top